防止在模板中转义正斜杠 [英] Prevent escaping forward slashes in templates

查看:106
本文介绍了防止在模板中转义正斜杠的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在努力将我的一个宠物项目从Python转换为Go,以帮助我熟悉该语言。我目前面临的一个问题是它正在逃避我的正斜杠。所以它会收到一个字符串:

  / location / to / something 

然后变成

 %2flocation%2fto% 2fsomething 

现在,只有当它在链接中时才会这样做(从我一直在阅读的内容转义是上下文的),所以这就是HTML模板中的行:

 < tr>< td><< ; a href =/ file?file = {{.FullFilePath}}> {{.FileName}}< / a>< / td>< / tr> 

如果可能的话,我该如何在模板或代码本身中防止它?



这就是我的模板函数的样子(是的,我知道它是黑客)

pre $ func renderTemplate(w http.ResponseWriter,tmpl字符串){
t,err:= template.ParseFiles(templates_dir +base.html,templates_dir + tmpl)
if err!= nil {
http.Error(w,err.Error(),http.StatusInternalServerError)
返回
}
如果tmpl ==view.html{
err = t.Execute( w,FileList)
} else {
err = t.Execute(w,nil)
}
if err!= nil {
http.Error(w, err.Error(),http.StatusInternalServerError)
}
}


解决方案

作为 .FullFilePath 的值,传递一个 template.URL 而不是 string ,它会告诉 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 =/文件?文件= {{.FileFullPath}}> {{.FileName}}< / a>< / td>< / tr>`

输出(尝试在 Go Playground ):

 < tr>< td>< a href =/ file?file = /位置/到/东西> something.txt< / A>< / TD>< / TR> 

请注意,即使正斜杠 / 是允许在URL中,模板包仍然对其进行编码的原因是因为它分析了URL并且发现要包含的值是URL参数的值( file = XXX ),所以它也编码了斜线(这样你传入的所有东西都将成为文件的一部分 $ b

如果您打算从URL参数获取服务器端的此文件路径,那么模板 code> package does not the correct and proper way。



但是要知道,通过这样做,您将失去防止代码注入URL的安全性。如果你是提供价值的人,并且你知道他们是安全的,那么没有问题。但是,如果数据来自用户输入,例如,不要这样做。



另外请注意,如果您传递整个URL(而不仅仅是它的一部分),它可以在不使用 template.URL 的情况下工作(在 Go Playground ):

  func main(){$ b $:bt:= template.Must template.New()。Parse(templ))
$ bm:bm:= 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路径的一部分,而不是作为参数的值,所以您应该像这样创建urls:

  / file / location / to / something 

映射您的处理程序(提供文件内容,请参阅此答案为例)到 / file / 模式,当它匹配并且你的处理程序被调用时,切断 / file / 前缀从路径 r.URL.Path ,其余的将是完整的文件路径。如果你选择这个,你也不需要 template.URL 转换(因为你包含的值不再是URL参数的值):



$ p $ 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>`

去游乐场试试这个。



同样非常重要:永远不要在处理函数中解析模板!详情请看:

使用模板时花费太多时间。包在golang中为客户端生成一个动态网页


I'm working on converting a pet project of mine from Python to Go just to help me get a bit familiar with the language. An issue I am currently facing is that it's escaping my forward slashes. So it will receive a string like:

/location/to/something

and it then becomes

%2flocation%2fto%2fsomething

Now, it's only doing this when it's in a link (from what I've been reading this escaping is contextual) so this is what the line in the HTML template looks like:

<tr><td><a href="/file?file={{.FullFilePath}}">{{.FileName}}</a></td></tr>

If possible, how can I prevent this in either the template or the code itself?

This is what my templating function looks like (yes, I know it's hackish)

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)
    }
}

解决方案

As the value of .FullFilePath, pass a value of type template.URL instead of string, which will tell the html/template package not to escape it.

For example:

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>`

Output (try it on the Go Playground):

<tr><td><a href="/file?file=/location/to/something">something.txt</a></td></tr>

Note that even though forward slashes / are allowed in URLs, the reason why the template package still encodes them is because it analyses the URL and sees that the value you want to include is the value of a URL parameter (file=XXX), and so it also encodes the slashes (so that everything you pass in will be part of the value of the file URL parameter).

If you plan to acquire this file path at the server side from URL parameters, then what the template package does is the correct and proper way.

But know that by doing this, you'll lose the safety that prevents code injection into URLs. If you're the one providing the values and you know they are safe, there is no problem. But if the data comes from a user input for example, never do this.

Also note that if you pass the whole URL (and not just a part of it), it will work without using template.URL (try this variant on the 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>`

Also note that the recommended way in my opinion would be to include the file path as part of the URL path and not as the value of a parameter, so instead you should create urls like this:

/file/location/to/something

Map your handler (which serves the file content, see this answer as an example) to the /file/ pattern, and when it is matched and your handler is called, cut off the /file/ prefix from the path r.URL.Path, and the rest will be the full file path. If you choose this, you also won't need the template.URL conversion (because the value you include is not a value of a URL parameter anymore):

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>`

Try this on the Go Playground.

Also very important: never parse templates in your handler functions! For details see:

It takes too much time when using "template" package to generate a dynamic web page to client in golang

这篇关于防止在模板中转义正斜杠的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆