防止转义模板中的正斜杠
Prevent escaping forward slashes in templates
我正在努力将我的一个宠物项目从 Python 转换为 Go,只是为了帮助我稍微熟悉一下这门语言。我目前面临的一个问题是它正在逃避我的正斜杠。所以它会收到一个像这样的字符串:
/location/to/something
然后变成
%2flocation%2fto%2fsomething
现在,它仅在 link 中执行此操作(根据我一直在阅读的内容,此转义是上下文相关的)所以这就是 HTML 模板中的行:
<tr><td><a href="/file?file={{.FullFilePath}}">{{.FileName}}</a></td></tr>
如果可能,我怎样才能在模板或代码本身中防止这种情况发生?
这就是我的模板函数的样子(是的,我知道它很老套)
func renderTemplate(w http.ResponseWriter, tmpl string) {
t, err := template.ParseFiles(templates_dir+"base.html", templates_dir+tmpl)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if tmpl == "view.html" {
err = t.Execute(w, FileList)
} else {
err = t.Execute(w, nil)
}
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
好的,所以我找到的解决方案(如果有更好的解决方案,请 post 解决)是基于 here.
的答案
我更改了我使用的结构:
type File struct {
FullFilePath string
FileName string
}
为此:
type File struct {
FullFilePath template.HTML
FileName string
}
并将 html 移动到 FullFilePath 名称中,然后将其放入 template.HTML 因此我生成的每个 FullFilePath 名称都是这样完成的:
file := File{template.HTML("<a href=\"/file?file=" + path + "\"</a>"), f.Name()}
我的模板文件行更改为:
<tr><td>{{.FullFilePath}}{{.FileName}}</td></tr>
作为.FullFilePath
的值,传一个template.URL
instead of string
, which will tell the html/template
包类型的值不转义。
例如:
func main() {
t := template.Must(template.New("").Parse(templ))
m := map[string]interface{}{
"FileName": "something.txt",
"FileFullPath": template.URL("/location/to/something"),
}
if err := t.Execute(os.Stdout, m); err != nil {
panic(err)
}
}
const templ = `<tr><td><a href="/file?file={{.FileFullPath}}">{{.FileName}}</a></td></tr>`
输出(在 Go Playground 上尝试):
<tr><td><a href="/file?file=/location/to/something">something.txt</a></td></tr>
请注意,即使在 URL 中允许使用正斜杠 /
,template
包仍然对其进行编码的原因是因为它分析了 URL 和看到您要包含的值是 URL 参数 (file=XXX
) 的值,因此它也对斜杠进行编码(这样您传入的所有内容都将成为 file
URL 参数).
如果你打算在服务器端从URL参数获取这个文件路径,那么template
包所做的是正确和正确的方法。
但是要知道,这样做会失去防止代码注入 URL 的安全性。如果您是提供这些值的人并且您知道它们是安全的,那么就没有问题。但是,如果数据来自用户输入,则永远不要这样做。
另请注意,如果您传递整个 URL(而不是其中的一部分),它会在不使用 template.URL
的情况下工作(在 Go Playground 上尝试此变体) :
func main() {
t := template.Must(template.New("").Parse(templ))
m := map[string]interface{}{
"FileName": "something.txt",
"FileURL": "/file?file=/location/to/something",
}
if err := t.Execute(os.Stdout, m); err != nil {
panic(err)
}
}
const templ = `<tr><td><a href="{{.FileURL}}">{{.FileName}}</a></td></tr>`
另请注意,我认为推荐的方法是将文件路径作为 URL 路径的一部分,而不是作为参数的值,因此您应该像这样创建 url:
/file/location/to/something
将您的处理程序(提供文件内容,参见 作为示例)映射到 /file/
模式,当它匹配并调用您的处理程序时,切断 /file/
前缀来自路径 r.URL.Path
,其余的将是完整的文件路径。如果你选择这个,你也不需要 template.URL
转换(因为你包含的值不再是 URL 参数的值):
func main() {
t := template.Must(template.New("").Parse(templ))
m := map[string]interface{}{
"FileName": "something.txt",
"FileFullPath": "/location/to/something",
}
if err := t.Execute(os.Stdout, m); err != nil {
panic(err)
}
}
const templ = `<tr><td><a href="/file{{.FileFullPath}}">{{.FileName}}</a></td></tr>`
在 Go Playground 上试试这个。
同样非常重要:永远不要在处理函数中解析模板!详情见:
It takes too much time when using "template" package to generate a dynamic web page to client in golang
我正在努力将我的一个宠物项目从 Python 转换为 Go,只是为了帮助我稍微熟悉一下这门语言。我目前面临的一个问题是它正在逃避我的正斜杠。所以它会收到一个像这样的字符串:
/location/to/something
然后变成
%2flocation%2fto%2fsomething
现在,它仅在 link 中执行此操作(根据我一直在阅读的内容,此转义是上下文相关的)所以这就是 HTML 模板中的行:
<tr><td><a href="/file?file={{.FullFilePath}}">{{.FileName}}</a></td></tr>
如果可能,我怎样才能在模板或代码本身中防止这种情况发生?
这就是我的模板函数的样子(是的,我知道它很老套)
func renderTemplate(w http.ResponseWriter, tmpl string) {
t, err := template.ParseFiles(templates_dir+"base.html", templates_dir+tmpl)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if tmpl == "view.html" {
err = t.Execute(w, FileList)
} else {
err = t.Execute(w, nil)
}
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
好的,所以我找到的解决方案(如果有更好的解决方案,请 post 解决)是基于 here.
的答案我更改了我使用的结构:
type File struct {
FullFilePath string
FileName string
}
为此:
type File struct {
FullFilePath template.HTML
FileName string
}
并将 html 移动到 FullFilePath 名称中,然后将其放入 template.HTML 因此我生成的每个 FullFilePath 名称都是这样完成的:
file := File{template.HTML("<a href=\"/file?file=" + path + "\"</a>"), f.Name()}
我的模板文件行更改为:
<tr><td>{{.FullFilePath}}{{.FileName}}</td></tr>
作为.FullFilePath
的值,传一个template.URL
instead of string
, which will tell the html/template
包类型的值不转义。
例如:
func main() {
t := template.Must(template.New("").Parse(templ))
m := map[string]interface{}{
"FileName": "something.txt",
"FileFullPath": template.URL("/location/to/something"),
}
if err := t.Execute(os.Stdout, m); err != nil {
panic(err)
}
}
const templ = `<tr><td><a href="/file?file={{.FileFullPath}}">{{.FileName}}</a></td></tr>`
输出(在 Go Playground 上尝试):
<tr><td><a href="/file?file=/location/to/something">something.txt</a></td></tr>
请注意,即使在 URL 中允许使用正斜杠 /
,template
包仍然对其进行编码的原因是因为它分析了 URL 和看到您要包含的值是 URL 参数 (file=XXX
) 的值,因此它也对斜杠进行编码(这样您传入的所有内容都将成为 file
URL 参数).
如果你打算在服务器端从URL参数获取这个文件路径,那么template
包所做的是正确和正确的方法。
但是要知道,这样做会失去防止代码注入 URL 的安全性。如果您是提供这些值的人并且您知道它们是安全的,那么就没有问题。但是,如果数据来自用户输入,则永远不要这样做。
另请注意,如果您传递整个 URL(而不是其中的一部分),它会在不使用 template.URL
的情况下工作(在 Go Playground 上尝试此变体) :
func main() {
t := template.Must(template.New("").Parse(templ))
m := map[string]interface{}{
"FileName": "something.txt",
"FileURL": "/file?file=/location/to/something",
}
if err := t.Execute(os.Stdout, m); err != nil {
panic(err)
}
}
const templ = `<tr><td><a href="{{.FileURL}}">{{.FileName}}</a></td></tr>`
另请注意,我认为推荐的方法是将文件路径作为 URL 路径的一部分,而不是作为参数的值,因此您应该像这样创建 url:
/file/location/to/something
将您的处理程序(提供文件内容,参见 /file/
模式,当它匹配并调用您的处理程序时,切断 /file/
前缀来自路径 r.URL.Path
,其余的将是完整的文件路径。如果你选择这个,你也不需要 template.URL
转换(因为你包含的值不再是 URL 参数的值):
func main() {
t := template.Must(template.New("").Parse(templ))
m := map[string]interface{}{
"FileName": "something.txt",
"FileFullPath": "/location/to/something",
}
if err := t.Execute(os.Stdout, m); err != nil {
panic(err)
}
}
const templ = `<tr><td><a href="/file{{.FileFullPath}}">{{.FileName}}</a></td></tr>`
在 Go Playground 上试试这个。
同样非常重要:永远不要在处理函数中解析模板!详情见:
It takes too much time when using "template" package to generate a dynamic web page to client in golang