Shiny, Let's Be Bad Guys: Exploiting and Mitigating the Top 10 Web App Vulnerabilities -- CodeMash 2017 edition
Slides from the CodeMash 2017 presentation of my tutorial that walks through the OWASP Top 10 web application vulnerabilities and discusses strategies to mitigate them.
PM • We’ll break midway through • Snacks & beverages available • Feedback via EventsXD mobile app • Slides linked from github repo Setup: https://github.com/mpirnat/lets-be-bad-guys
Non-profit focused on improving software security • Documentation and tools to help learn about security and protect your apps Setup: https://github.com/mpirnat/lets-be-bad-guys
security firms • Over 500,000 vulnerabilities, hundreds of orgs, thousands of apps • Selected & prioritized by prevalence data combined with estimates of exploitability, detectability, and impact • Updated in 2013 (refresh coming in 2017) Setup: https://github.com/mpirnat/lets-be-bad-guys
it! • Discuss prevention • Django & Flask specific advice where possible • Light examples where we have time Setup: https://github.com/mpirnat/lets-be-bad-guys
of a SQL query and allows a malicious query to be executed... """ select * from users where username='%s'; """ • Use 2 dashes to start a SQL comment: -- • http://localhost:8000/injection/sql
accept if signature is bogus/missing • Use ORMs or bind variables when talking to the database • Don’t use eval or exec, beware of pickle, user-supplied YAML, etc.
are tight • Use Forms instead of ModelForms • Make new validators as needed for your application • Make sure your URL regexes for dynamic URLs are tight
... WHERE foo = %s", params={'foo': ...}) # If it's more complicated: from django.db import connection cursor = connection.cursor() cursor.execute("UPDATE bar set bar = 1 WHERE foo < %s", [foo]) row = cursor.fetchall()
be easily overwritten • Don’t put session IDs in URLs • Allow session IDs to timeout/log out • Rotate session IDs after successful login • TLS connections for passwords, session IDs
message forum, comment, etc. • Reflected: injected code in live request to server, reflected back in error message or search result • DOM: injected code in browser DOM environment that causes scripts to run in unexpected ways (eg, reading from URL)
to other users (comments, messages) • Form inputs where value is populated with user-supplied data • Script tags where user-supplied data is populated into script variables
is variable, isn’t validated, and gets included into the page: http://example.com/stuff/{$CATEGORY} • http://localhost:8000/cross-site- scripting/path-matching/your-path- here
a query string parameter is included in the page: http://example.com/?search={$TEXT} • http://localhost:8000/cross-site- scripting/query-params?qs=awesome
input is prematurely terminated, allowing Javascript to be injected into or adjacent to the element: <input … value="{$TEXT}"> • http://localhost:8000/cross-site- scripting/form-field
context the data will be placed into • Whitelist input validation • Consider auto-sanitization libraries for rich content (eg, OWASP’s AntiSamy) • Update your parents’/in-laws’ browsers!
behavior • Use X-Frame-Options header to control whether and how a page can be loaded within a frame • Use Content-Security-Policy header to specify where a page can load resources from (requires careful tuning)
etc. • Use form.as_p, form.as_table, form.as_ul when displaying a form in a template • Be careful with your own template tags; django.utils.html.escape is your friend!
• Keep your SECRET_KEY secret! • Keep Python code out of webserver’s root • Don’t run admin publicly • Don’t use the built-in admin for normal user admin tasks
tax IDs, authentication credentials, etc. • Sensitive data deserves extra protection such as encryption at rest or in transit, special precautions when exchanged with the browser
protect the confidentiality and integrity of sensitive network traffic • May use weak algorithms • May use expired or invalid certificates • May use certificates incorrectly
backups; manage keys separately • Use strong standard algorithms, strong keys • Hash passwords with strong standard algorithm & use appropriate salt • Protect passwords & keys from unauthorized access
requests to SSL • Set the “secure” flag on sensitive cookies • Use only strong SSL algorithms • Ensure your cert is valid, not expired, not revoked, and matches your domain • SSL/encryption on the back end too
against downgrade attacks and cookie hijacking •Consider setting Public Key Pinning (HPKP) header to reduce impersonation by attackers with mis-issued or fraudulent certificates
hashing • Use bcrypt or Argon2; see https:// docs.djangoproject.com/en/1.10/topics/auth/ passwords/ • Require SSL in Apache or Nginx • Require SSL using middleware: • Configure Django SecurityMiddleware–introduced in Django 1.8! • https://docs.djangoproject.com/en/1.10/ref/middleware/ • https://github.com/rdegges/django-sslify
Require SSL: • https://github.com/kennethreitz/flask-sslify • https://github.com/jacobian/wsgi-sslify • Use Passlib to do bcrypt or Argon2: • https://passlib.readthedocs.io/en/stable/
authentication is required, make sure that checks are in place • If additional authorization is required, make sure that checks are in place • Deny all by default; explicitly grant access to users or roles
victim is allowed to change • Cause victim to perform any function the victim is authorized to use • Impact varies based on victim’s role • Think of some possibilities...
a unique token in a hidden field (often used in concert with a cookie) • Validate token to make sure the request is from on-site • Avoid putting the token into a query string
use the CSRF middleware and template tag in forms • Be VERY CAREFUL about deactivating it (csrf_exempt decorator) • Be careful about APIs (Tastypie, oauth); http://codrspace.com/vote539/csrf- protection-in-django-tastypie/
modules almost always run with full privilege • Hard to stay up to date on everything • Do you even know all the components in use, let alone their versions? • Components with known problems can be identified & exploited with automated tools
more selectively with whitelist, using cookies for previous URL: http://flask.pocoo.org/snippets/120/ • Can modify these approaches to suit, as with the Django example