Created
March 12, 2022 17:16
-
-
Save vincd/25c762d947a49a41ebb1dbad82a17a84 to your computer and use it in GitHub Desktop.
Security Header example server : https//unbonhacker.com/posts/security-headers/
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
```bash | |
pip install flask | |
python server.py | |
``` | |
The serveur use http://127.0.0.1:8000 and http://localhost:8000 as two differents | |
origins. So remember to test with this two URLs. | |
""" | |
from flask import Flask, Response, request | |
app = Flask(__name__) | |
PORT = 8000 | |
REFERRER_POLICY = [ | |
'no-referrer', | |
'no-referrer-when-downgrade', | |
'origin', | |
'origin-when-cross-origin', | |
'same-origin', | |
'strict-origin', | |
'strict-origin-when-cross-origin', | |
'unsafe-url' | |
] | |
# Shortcut to create a Flask response | |
def render(body, headers): | |
return Response(f'<!DOCTYPE html><html><body>{body}</body></html>', headers=headers) | |
@app.route('/') | |
def index(): | |
body = '<h1>HTTP Security Headers Demonstration</h1><ul>' | |
# body += '<li><a href="/Strict-Transport-Security">Strict-Transport-Security</a></li>' | |
body += '<li><a href="/X-Frame-Options">X-Frame-Options</a></li>' | |
body += '<li><a href="/Cross-Origin-Resource-Sharing">Cross-Origin-Resource-Sharing</a></li>' | |
body += '<li><a href="/Content-Security-Policy">Content-Security-Policy</a></li>' | |
body += '<li><a href="/X-Content-Type-Options">X-Content-Type-Options</a></li>' | |
body += '<li><a href="/Referrer-Policy">Referrer-Policy</a></li>' | |
# body += '<li><a href="/X-XSS-Protection">X-XSS-Protection</a></li>' | |
body += '<li><a href="/Set-Cookie">Set-Cookie</a></li>' | |
# body += '<li><a href="/Cross-Origin-Opener-Policy">Cross-Origin-Opener-Policy</a></li>' | |
body += '</ul>' | |
return render(body, {}) | |
@app.route('/Strict-Transport-Security') | |
def StrictTransportSecurity(): | |
return render('<h1>Strict-Transport-Security</h1>', {}) | |
@app.route('/X-Frame-Options') | |
def XFrameOptions(): | |
body = '<h1>X-Frame-Options</h1>' | |
headers = {} | |
frame = request.args.get('frame', '') | |
if frame != '': | |
body += f'<p>Page with origin http://localhost:{PORT} and header "{frame}"</p>' | |
body += '<form><select name="frame">' | |
body += '<option value="deny">Deny frame</option>' | |
body += '<option value="sameorigin">Allow from same origin</option>' | |
body += '<option value="no-header">No header</option>' | |
body += '</select><button>Go</button></form>' | |
else: | |
body += f'<p>This page include an other page included. Use <a href="http://127.0.0.1:{PORT}/X-Frame-Options">127.0.0.1</a> or <a href="http://localhost:{PORT}/X-Frame-Options">localhost</a> as 2 diffrents origins!</p>' | |
body += '<form><button>RELOAD FRAME</button></form>' | |
body += f'<iframe src="http://localhost:{PORT}/X-Frame-Options?frame=no-header"></iframe>' | |
if frame == 'deny': | |
headers['X-Frame-Options'] = 'DENY' | |
elif frame == 'sameorigin': | |
headers['X-Frame-Options'] = 'SAMEORIGIN' | |
return render(body, headers) | |
@app.route("/scripts/bad_cors.js") | |
def script_bad_cors(): | |
headers = { | |
"Content-Type": "application/json", | |
"Access-Control-Allow-Origin": "*" | |
} | |
return Response('{"msg": "This ressource comes from an other origin!"}', headers=headers) | |
@app.route("/scripts/good_cors.js") | |
def script_good_cors(): | |
headers = { | |
"Content-Type": "application/json", | |
"Access-Control-Allow-Origin": f"http://localhost:{PORT}" | |
} | |
return Response('{"msg": "This ressource comes from an other origin!"}', headers=headers) | |
@app.route('/Cross-Origin-Resource-Sharing') | |
def CrossOriginResourceSharing(): | |
body = '<h1>Cross-Origin-Resource-Sharing</h1>' | |
cors = request.args.get('cors', '') | |
url = f'http://localhost:{PORT}/scripts/bad_cors.js' if cors == 'allow' else f'http://localhost:{PORT}/scripts/good_cors.js' | |
body += '<form><select name="cors">' | |
body += '<option value="allow">Allow from other site</option>' | |
body += '<option value="deny">Deny from other site</option>' | |
body += '</select><button>Go</button></form>' | |
body += f'<script>fetch("{url}").then(r => r.json()).then(data => alert(data.msg));</script>' | |
return render(body, {}) | |
@app.route("/scripts/csp.js") | |
def script_csp(): | |
return f'alert("This script is from a file")' | |
@app.route('/Content-Security-Policy') | |
def ContentSecurityPolicy(): | |
body = '<h1>Content-Security-Policy</h1>' | |
headers = {} | |
csp = request.args.get('csp', '') | |
body += '<form><select name="csp">' | |
body += '<option value="none">script-src: none</option>' | |
body += '<option value="self">script-src: \'self\'</option>' | |
body += '<option value="unsafe-inline">script-src: unsafe-inline</option>' | |
body += '<option value="nothing">No header</option>' | |
body += '</select><button>Go</button></form><script>alert("This script is inline");</script><script src="/scripts/csp.js"></script>' | |
if csp == 'none': | |
headers['Content-Security-Policy'] = 'script-src none;' | |
elif csp == 'self': | |
headers['Content-Security-Policy'] = 'script-src \'self\';' | |
elif csp == 'unsafe-inline': | |
headers['Content-Security-Policy'] = 'script-src \'unsafe-inline\';' | |
return render(body, headers) | |
@app.route('/scripts/plain_text.js') | |
def scripts_plain_text(): | |
headers = {} | |
ctopt = request.args.get('ctopt') | |
if ctopt == 'nosniff': | |
headers['X-Content-Type-Options'] = 'nosniff' | |
return Response('alert("Script executed with Content-Type: plain/text")', headers=headers) | |
@app.route('/X-Content-Type-Options') | |
def XContentTypeOptions(): | |
body = '<h1>X-Content-Type-Options</h1>' | |
headers = {} | |
ctopt = request.args.get('ctopt') | |
body += '<form><select name="ctopt">' | |
body += '<option value="nosniff">X-Content-Type-Options: nosniff</option>' | |
body += '<option value="">No header X-Content-Type-Options</option>' | |
body += f'</select><button>Go</button></form><script src="/scripts/plain_text.js?ctopt={ctopt}"></script>' | |
return render(body, headers) | |
@app.route("/scripts/referrer.js") | |
def script_referrer(): | |
referrer = request.headers.get('Referer', '') | |
return f'alert("Referer header value: \\"{referrer}\\"")' | |
@app.route('/Referrer-Policy') | |
def ReferrerPolicy(): | |
ref = request.args.get('referrer') | |
if not ref in REFERRER_POLICY: | |
ref = '' | |
body = '<h1>Referrer-Policy</h1><form><select name="referrer">' | |
for r in REFERRER_POLICY: | |
body += f'<option value="{r}">{r}</option>' | |
body += '</select><button>Go</button></form><script src="/scripts/referrer.js"></script>' | |
headers = {} | |
if ref != '': | |
headers["Referrer-Policy"] = ref | |
return render(body, headers) | |
@app.route('/X-XSS-Protection') | |
def XXSSProtection(): | |
return render('<h1>X-XSS-Protection</h1>', {}) | |
@app.route("/scripts/cookies.js") | |
def script_cookies(): | |
cookies = request.headers['cookie'] | |
return f'alert("Cookies from headers: {cookies}"); alert("Cookies from Javascript:" + document.cookie)' | |
@app.route('/Set-Cookie') | |
def SetCookie(): | |
body = '<h1>Set-Cookie</h1><form><select name="cookie">' | |
body += '<option value="httponly">Cookie with HttpOnly</option>' | |
body += '<option value="no-httponly">Cookie without HttpOnly</option>' | |
body += '<option value="remove">Remove cookie</option>' | |
body += '</select><button>Go</button></form><script src="/scripts/cookies.js"></script>' | |
cookie = request.args.get('cookie', '') | |
headers = {} | |
if cookie == 'httponly': | |
headers['Set-Cookie'] = 'TestCookie=TestWithHttpOnly; path=/; httpOnly; SameSite=Lax' | |
elif cookie == 'no-httponly': | |
headers['Set-Cookie'] = 'TestCookie=TestWithHttpOnly; path=/; SameSite=Lax' | |
elif cookie == 'remove': | |
headers['Set-Cookie'] = 'TestCookie=Delete; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=Lax' | |
return render(body, headers) | |
if __name__ == "__main__": | |
app.run( | |
host="127.0.0.1", | |
port=PORT, | |
debug=True | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment