2016-06-26 6 views
2

Ich arbeite an der Konvertierung eines Pet-Projekts von mir von Python nach Go, nur um mir ein bisschen vertraut mit der Sprache zu helfen. Ein Problem, mit dem ich derzeit konfrontiert bin, ist, dass es meinen Vorwärtsstrichen entgeht. So wird es eine Zeichenfolge wie erhalten:Verhindere das Entweichen von Schrägstrichen in Vorlagen

/location/to/something 

und es wird dann

%2flocation%2fto%2fsomething 

Nun, es ist nur das tun, wenn es in einem Link ist (von dem, was ich habe dieses Entkommen gelesen kontextuelle ist) so ist es das, was in der HTML-Vorlage die Zeilen wie folgt aussehen:

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

Wenn möglich, wie kann ich das verhindern entweder in der Vorlage oder den Code selbst?

Dies ist, was meine Templating Funktion sieht aus wie (ja, ich weiß, es hackish ist)

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

Mögliches Duplikat [auto Flucht in HTML-Vorlage vermeiden] (http://stackoverflow.com/questions/36980049/avoid-auto-escape-in-html-template) – icza

+0

@ Icza, danke, dass Sie mich auf diesen Link verwiesen haben, aber ich kann nicht sehen, wie ich diese Lösung hier umsetzen kann. Ich bin zugegebenermaßen immer noch ein Noob, vielleicht deshalb. Ich habe am Ende eine andere Frage gefunden, deren Lösung mir geholfen hat, also habe ich das hier gepostet. – basica

+1

Siehe meine Antwort unten. – icza

Antwort

2

Da der Wert von .FullFilePath, einen Wert vom Typ passieren template.URL statt string, die die html/template Paket sagen wird, es nicht zu entkommen.

Zum Beispiel:

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 (versuchen Sie es auf dem Go Playground):

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

Beachten Sie, dass, obwohl nach vorn / Schrägstriche sind in URLs erlaubt, den Grund, warum die template Paket kodiert noch Das liegt daran, dass es die URL analysiert und erkennt, dass der Wert, den Sie angeben möchten, der Wert eines URL-Parameters ist (file=XXX), und so werden auch die Schrägstriche codiert (so dass alles, was Sie übergeben, ist) Teil des Wertes des URL-Parameters file).

Wenn Sie diesen Dateipfad auf der Serverseite von URL-Parametern erwerben möchten, dann ist das template-Paket der richtige und richtige Weg.

Aber wissen Sie, dass Sie dadurch die Sicherheit verlieren, die die Code-Injektion in URLs verhindert. Wenn Sie die Werte angeben und wissen, dass sie sicher sind, gibt es kein Problem. Wenn die Daten jedoch beispielsweise von einer Benutzereingabe stammen, tun Sie dies nie.

Beachten Sie auch, dass, wenn Sie die gesamte URL (und nicht nur ein Teil davon) übergeben, wird es ohne template.URL arbeiten (versuchen Sie diese Variante auf der 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>` 

Beachten Sie auch, dass die empfohlene Art und Weise meiner Meinung nach wäre es, den Dateipfad als Teil des URL-Pfad enthalten und nicht als Wert eines Parameters, so stattdessen sollten Sie Urls wie folgt erstellen:

/file/location/to/something 

Karte Handler (die die Datei dient Inhalt, siehe this answer als Beispiel) zu dem /file/ Muster, und wenn es übereinstimmt und Ihr Handler aufgerufen wird, schneiden Sie das /file/ Präfix aus dem Pfad r.URL.Path, und der Rest wird der vollständige Dateipfad sein. Wenn Sie diese Option auswählen, werden Sie auch nicht brauchen die template.URL Umwandlung (weil der Wert, den Sie enthalten kein Wert eines URL-Parameters ist mehr):

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

die Sie interessieren auf dem Go Playground.

Auch sehr wichtig: Templates nie in Ihren Handler-Funktionen analysieren! Details siehe:

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

+0

Danke, das wird sehr geschätzt. Danke für die Erklärung der Sicherheitsrisiken, in meinem Fall ist es nicht anwendbar (das ist nur etwas, das ich zu Hause benutze, nicht öffentlich), aber es ist nützlich für andere zu wissen. – basica

+1

@basica Siehe auch den Hinweis am Ende hinzugefügt: Templates nie in den Handler-Funktionen zu analysieren (es ist langsam, und sollte vor dem Aufruf von Handler getan werden). – icza

0

OK, also die Lösung, die ich gefunden habe (und bitte posten, wenn es ein besseres ist) auf ein basiert Antwort here.

änderte ich die Struktur I aus wurde mit:

type File struct { 
    FullFilePath string 
    FileName  string 
} 

Um dies:

type File struct { 
    FullFilePath template.HTML 
    FileName  string 
} 

und zog den HTML-Code in den FullFilePath Namen und stellte dann, dass in template.html so jeder FullFilePath name war Erzeugen ich war wie so getan:

file := File{template.HTML("<a href=\"/file?file=" + path + "\"</a>"), f.Name()} 

Und meine Vorlagendatei Linie war chan ged dazu:

<tr><td>{{.FullFilePath}}{{.FileName}}</td></tr>