Merge branch '253-security-headers' of https://github.com/mig5/onionshare into mig5-253-security-headers

This commit is contained in:
Micah Lee 2017-05-22 14:56:32 -07:00
commit e01716bca9
No known key found for this signature in database
GPG Key ID: 403C2657CD994F73

View File

@ -21,7 +21,7 @@ from distutils.version import StrictVersion as Version
import queue, mimetypes, platform, os, sys, socket, logging import queue, mimetypes, platform, os, sys, socket, logging
from urllib.request import urlopen from urllib.request import urlopen
from flask import Flask, Response, request, render_template_string, abort from flask import Flask, Response, request, render_template_string, abort, make_response
from flask import __version__ as flask_version from flask import __version__ as flask_version
from . import strings, common from . import strings, common
@ -47,6 +47,16 @@ file_info = []
zip_filename = None zip_filename = None
zip_filesize = None zip_filesize = None
strings.load_strings(common)
security_headers = [
('Content-Security-Policy', 'default-src \'self\'; style-src \'unsafe-inline\'; img-src \'self\' data:;'),
('X-Frame-Options', 'DENY'),
('X-Xss-Protection', '1; mode=block'),
('X-Content-Type-Options', 'nosniff'),
('Referrer-Policy', 'no-referrer'),
('Server', strings._('version_string').format(common.get_version()))
]
def set_file_info(filenames, processed_size_callback=None): def set_file_info(filenames, processed_size_callback=None):
""" """
Using the list of filenames being shared, fill in details that the web Using the list of filenames being shared, fill in details that the web
@ -175,16 +185,23 @@ def index(slug_candidate):
global stay_open, download_in_progress global stay_open, download_in_progress
deny_download = not stay_open and download_in_progress deny_download = not stay_open and download_in_progress
if deny_download: if deny_download:
return render_template_string(open(common.get_resource_path('html/denied.html')).read()) r = make_response(render_template_string(open(common.get_resource_path('html/denied.html')).read()))
for header,value in security_headers:
r.headers.set(header, value)
return r
# If download is allowed to continue, serve download page # If download is allowed to continue, serve download page
return render_template_string(
r = make_response(render_template_string(
open(common.get_resource_path('html/index.html')).read(), open(common.get_resource_path('html/index.html')).read(),
slug=slug, slug=slug,
file_info=file_info, file_info=file_info,
filename=os.path.basename(zip_filename), filename=os.path.basename(zip_filename),
filesize=zip_filesize, filesize=zip_filesize,
filesize_human=common.human_readable_filesize(zip_filesize)) filesize_human=common.human_readable_filesize(zip_filesize)))
for header,value in security_headers:
r.headers.set(header, value)
return r
# If the client closes the OnionShare window while a download is in progress, # If the client closes the OnionShare window while a download is in progress,
# it should immediately stop serving the file. The client_cancel global is # it should immediately stop serving the file. The client_cancel global is
@ -203,7 +220,10 @@ def download(slug_candidate):
global stay_open, download_in_progress global stay_open, download_in_progress
deny_download = not stay_open and download_in_progress deny_download = not stay_open and download_in_progress
if deny_download: if deny_download:
return render_template_string(open(common.get_resource_path('html/denied.html')).read()) r = make_response(render_template_string(open(common.get_resource_path('html/denied.html')).read()))
for header,value in security_headers:
r.headers.set(header, value)
return r
global download_count global download_count
@ -286,13 +306,14 @@ def download(slug_candidate):
shutdown_func() shutdown_func()
r = Response(generate()) r = Response(generate())
r.headers.add('Content-Length', zip_filesize) r.headers.set('Content-Length', zip_filesize)
r.headers.add('Content-Disposition', 'attachment', filename=basename) r.headers.set('Content-Disposition', 'attachment', filename=basename)
for header,value in security_headers:
r.headers.set(header, value)
# guess content type # guess content type
(content_type, _) = mimetypes.guess_type(basename, strict=False) (content_type, _) = mimetypes.guess_type(basename, strict=False)
if content_type is not None: if content_type is not None:
r.headers.add('Content-Type', content_type) r.headers.set('Content-Type', content_type)
return r return r
@ -311,7 +332,10 @@ def page_not_found(e):
force_shutdown() force_shutdown()
print(strings._('error_rate_limit')) print(strings._('error_rate_limit'))
return render_template_string(open(common.get_resource_path('html/404.html')).read()) r = make_response(render_template_string(open(common.get_resource_path('html/404.html')).read()))
for header,value in security_headers:
r.headers.set(header, value)
return r
# shutting down the server only works within the context of flask, so the easiest way to do it is over http # shutting down the server only works within the context of flask, so the easiest way to do it is over http
shutdown_slug = common.random_string(16) shutdown_slug = common.random_string(16)