From f74d2a8c3e3b1e8e336678d2899facd5bcdb589f Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Fri, 12 Jun 2015 02:36:16 +0200 Subject: [PATCH] Added REDIRECT_ALLOW_TARGET option (defaults to HTTP referer). --- server/gae-go/app/main.go | 30 ++++++++++++++++++++++++++++-- server/gae-python/main.py | 21 +++++++++++++++++++-- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/server/gae-go/app/main.go b/server/gae-go/app/main.go index c385ccb48..6900ed12b 100644 --- a/server/gae-go/app/main.go +++ b/server/gae-go/app/main.go @@ -1,5 +1,5 @@ /* - * jQuery File Upload Plugin GAE Go Example 4.0.0 + * jQuery File Upload Plugin GAE Go Example 4.1.0 * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2011, Sebastian Tschan @@ -44,6 +44,9 @@ const ( THUMB_MAX_WIDTH = 80 THUMB_MAX_HEIGHT = 80 EXPIRATION_TIME = 300 // seconds + // If empty, only allow redirects to the referer protocol+host. + // Set to a regexp string for custom pattern matching: + REDIRECT_ALLOW_TARGET = "" ) var ( @@ -220,6 +223,29 @@ func handleUploads(r *http.Request) (fileInfos []*FileInfo) { return } +func validateRedirect(r *http.Request, redirect string) bool { + if redirect != "" { + var redirectAllowTarget *regexp.Regexp + if REDIRECT_ALLOW_TARGET != "" { + redirectAllowTarget = regexp.MustCompile(REDIRECT_ALLOW_TARGET) + } else { + referer := r.Referer() + if referer == "" { + return false + } + refererUrl, err := url.Parse(referer) + if err != nil { + return false + } + redirectAllowTarget = regexp.MustCompile("^" + regexp.QuoteMeta( + refererUrl.Scheme + "://" + refererUrl.Host + "/", + )) + } + return redirectAllowTarget.MatchString(redirect) + } + return false +} + func get(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/" { http.Redirect(w, r, WEBSITE, http.StatusFound) @@ -254,7 +280,7 @@ func post(w http.ResponseWriter, r *http.Request) { result["files"] = handleUploads(r) b, err := json.Marshal(result) check(err) - if redirect := r.FormValue("redirect"); redirect != "" { + if redirect := r.FormValue("redirect"); validateRedirect(r, redirect) { if strings.Contains(redirect, "%s") { redirect = fmt.Sprintf( redirect, diff --git a/server/gae-python/main.py b/server/gae-python/main.py index f6a0c4e4a..77272c412 100644 --- a/server/gae-python/main.py +++ b/server/gae-python/main.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# jQuery File Upload Plugin GAE Python Example 3.0.0 +# jQuery File Upload Plugin GAE Python Example 3.1.0 # https://github.com/blueimp/jQuery-File-Upload # # Copyright 2011, Sebastian Tschan @@ -28,6 +28,9 @@ THUMB_MAX_HEIGHT = 80 THUMB_SUFFIX = '.'+str(THUMB_MAX_WIDTH)+'x'+str(THUMB_MAX_HEIGHT)+'.png' EXPIRATION_TIME = 300 # seconds +# If set to None, only allow redirects to the referer protocol+host. +# Set to a regexp for custom pattern matching against the redirect value: +REDIRECT_ALLOW_TARGET = None class CORSHandler(webapp2.RequestHandler): def cors(self): @@ -60,6 +63,20 @@ def validate(self, file): return True return False + def validate_redirect(self, redirect): + if redirect: + if REDIRECT_ALLOW_TARGET: + return REDIRECT_ALLOW_TARGET.match(redirect) + referer = self.request.headers['referer'] + if referer: + from urlparse import urlparse + parts = urlparse(referer) + redirect_allow_target = '^' + re.escape( + parts.scheme + '://' + parts.netloc + '/' + ) + return re.match(redirect_allow_target, redirect) + return False + def get_file_size(self, file): file.seek(0, 2) # Seek to the end of the file size = file.tell() # Get the position of EOF @@ -131,7 +148,7 @@ def post(self): result = {'files': self.handle_upload()} s = self.json_stringify(result) redirect = self.request.get('redirect') - if redirect: + if self.validate_redirect(redirect): return self.redirect(str( redirect.replace('%s', urllib.quote(s, ''), 1) ))