Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
??? 099112c May 21, 2019
1 contributor

Users who have contributed to this file

executable file 166 lines (135 sloc) 7.53 KB
#!/usr/bin/python2.7
import sys
import requests
from urlparse import urlparse
from termcolor import colored
import tldextract
# Sources:
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
# https://content-security-policy.com/
t_help = {
"child-src": "Defines the valid sources for web workers and nested browsing contexts loaded using elements such as <frame> and <iframe>.",
"connect-src": "Restricts the URLs which can be loaded using script interfaces",
"default-src": "Serves as a fallback for the other fetch directives.",
"font-src": "Specifies valid sources for fonts loaded using @font-face.",
"frame-src": "Specifies valid sources for nested browsing contexts loading using elements such as <frame> and <iframe>.",
"img-src": "Specifies valid sources of images and favicons.",
"manifest-src": "Specifies valid sources of application manifest files.",
"media-src": "Specifies valid sources for loading media using the <audio> , <video> and <track> elements.",
"object-src": "Specifies valid sources for the <object>, <embed>, and <applet> elements.",
"prefetch-src": "Specifies valid sources to be prefetched or prerendered.",
"script-src": "Specifies valid sources for JavaScript.",
"style-src": "Specifies valid sources for stylesheets.",
"webrtc-src": "Specifies valid sources for WebRTC connections.",
"worker-src": "Specifies valid sources for Worker, SharedWorker, or ServiceWorker scripts.",
"base-uri": "Restricts the URLs which can be used in a document's <base> element.",
"plugin-types": "Restricts the set of plugins that can be embedded into a document by limiting the types of resources which can be loaded.",
"sandbox": "Enables a sandbox for the requested resource similar to the <iframe> sandbox attribute.",
"disown-opener": "Ensures a resource will disown its opener when navigated to.",
"form-action": "Restricts the URLs which can be used as the target of a form submissions from a given context.",
"frame-ancestors": "Specifies valid parents that may embed a page using <frame>, <iframe>, <object>, <embed>, or <applet>.",
"navigate-to": "Restricts the URLs to which a document can navigate by any means (a, form, window.location, window.open, etc.)",
"report-uri": "Instructs the user agent to report attempts to violate the Content Security Policy. These violation reports consist of JSON documents sent via an HTTP POST request to the specified URI.",
"report-to": "Fires a SecurityPolicyViolationEvent.",
"block-all-mixed-content": "Prevents loading any assets using HTTP when the page is loaded using HTTPS.",
"referrer": "Used to specify information in the referer (sic) header for links away from a page. Use the Referrer-Policy header instead.",
"require-sri-for": "Requires the use of SRI for scripts or styles on the page.",
"upgrade-insecure-requests": "Instructs user agents to treat all of a site's insecure URLs (those served over HTTP) as though they have been replaced with secure URLs (those served over HTTPS). This directive is intended for web sites with large numbers of insecure legacy URLs that need to be rewritten.",
"*": {"t":"Wildcard, allows any URL except data: blob: filesystem: schemes.","c":"red"},
"'none'": {"t":"Prevents loading resources from any source.","c":"green"},
"'self'": {"t":"Allows loading resources from the same origin (same scheme, host and port).","c":"green"},
"data:": {"t":"Allows loading resources via the data scheme (eg Base64 encoded images).","c":"yellow"},
"blob:": {"t":"Allows loading resources via the blob scheme (eg Base64 encoded images).","c":"yellow"},
"domain.example.com": {"t":"Allows loading resources from the specified domain name.","c":"green"},
"*.example.com": {"t":"Allows loading resources from any subdomain under example.com.","c":"green"},
"https://cdn.com": {"t":"Allows loading resources only over HTTPS matching the given domain.","c":"green"},
"https:": {"t":"Allows loading resources only over HTTPS on any domain.","c":"green"},
"'unsafe-inline'": {"t":"Allows use of inline source elements such as style attribute, onclick, or script tag bodies (depends on the context of the source it is applied to) and javascript: URIs.","c":"red"},
"'unsafe-eval'": {"t":"Allows unsafe dynamic code evaluation such as JavaScript eval()","c":"red"},
"'nonce-'": {"t":"Allows script or style tag to execute if the nonce attribute value matches the header value. Note that 'unsafe-inline' is ignored if either a hash or nonce value is present in the source list.","c":"green"},
"'sha256-'": {"t":"Allow a specific script or style to execute if it matches the hash. Doesn't work for javascript: URIs. Note that 'unsafe-inline' is ignored if either a hash or nonce value is present in the source list.","c":"green"},
}
t_warning_level = {
0: 'white',
1: 'cyan',
2: 'green',
3: 'yellow',
4: 'red',
}
def usage( err='' ):
print( "Usage: %s <url>" % sys.argv[0] )
if err:
print( "Error: %s!" % err )
sys.exit()
if len(sys.argv) < 2:
usage( 'url not found' )
if len(sys.argv) > 2:
usage()
url = sys.argv[1]
if not url.startswith('http'):
url = 'https://' + url
print("Calling %s..." % url )
r = requests.get( url )
if 'Content-Security-Policy' not in r.headers:
usage( 'Content-Security-Policy not found' )
#print("%s" % r.headers['Content-Security-Policy'] )
t_csp = r.headers['Content-Security-Policy'].split( ';' )
#print(" %s" % t_csp )
print("")
t_parse_orig = urlparse( url )
t_tld_orig = tldextract.extract( t_parse_orig.netloc )
# print( t_parse_orig )
def getWarningLevel( t_tld_orig, item ):
w_level = 0
if item in t_help:
return 0
if not item.startswith('http'):
item = 'https://'+item
tmp_parse = urlparse( item )
tmp_tld = tldextract.extract( tmp_parse.netloc )
# print(tmp_parse)
if tmp_tld.subdomain == t_tld_orig.subdomain and tmp_tld.domain == t_tld_orig.domain and tmp_tld.suffix == t_tld_orig.suffix:
w_level = 1
elif tmp_tld.domain == t_tld_orig.domain and tmp_tld.suffix == t_tld_orig.suffix:
w_level = 2
else:
w_level = 3
if '*' in tmp_parse.netloc:
w_level+=1
return w_level
for csp in t_csp:
csp = csp.strip()
if not len(csp):
continue
tmp = csp.split( ' ' )
policy = tmp.pop( 0 )
if policy:
if not len(policy):
continue
#sys.stdout.write( " " )
sys.stdout.write( colored( "%s" % policy, 'cyan', attrs=['reverse'] ) )
if policy in t_help:
sys.stdout.write( colored( " [%s]" % t_help[policy], 'white' ) )
sys.stdout.write( "\n" )
for item in tmp:
if not len(item):
continue
orig_item = item
if item.startswith("'nonce-"):
item = "'nonce-'"
elif item.startswith("'sha256-"):
item = "'sha256-'"
if item in t_help:
color = t_help[item]['c']
else:
w_level = getWarningLevel( t_tld_orig, item )
color = t_warning_level[w_level]
if color == 'white':
sys.stdout.write( " + " ) # can't print white with colored
else:
sys.stdout.write( colored( " + ", color ) )
sys.stdout.write( "%s" % orig_item )
if item in t_help:
sys.stdout.write( colored( " [%s]" % t_help[item]['t'], color ) )
sys.stdout.write( "\n" )
sys.stdout.write( "\n" )
You can’t perform that action at this time.