web app security notes

Security principles to live by

  • never trust the frontend; seriously don't trust us! (because frontend can easily be bypassed or attacked)
  • defense in depth; multiple not just 1 security check e.g. 2fa, csrf and same site, client and server checks 
  • principle of least privilege, users lowest set of privileges by default



OWASP Top 10 security risks for Web Applications is a good guide to identifying what risks app builders should be securing again. Injection (including xss) is still in the top 3. The OWASP Cheat Sheet is a good resource too for problems and solutions. Lets look at some top ones:

#1 Broken Access Control; exposure/modification/removal of information by unauthorized users.

  • are access controls consistently applied everywhere needed? e.g. menus vs deep links to pages; apis not consistently enforcing auth checks
  • what if bypass ui controls and hit apis directly?

#2 Cryptographic failures; crypto failures can lead to exposure of sensitive data

  • is sensitive data properly protected and adhere to laws such as GDPR? e.g. PII info
  • old or weak crypto algorithms; weak keys; use of https 
#3 Injection; including xss and sql injection; can lead to data exposure and unauthorized access.
  • xss: attacker exploits vulnerability to inject and run an evil script in users browser
  • apis need to validate input (don't trust the client) before persisting;
    • attackers look for ways for xss input to make it's way into the html output
  • apis not trust and use unchecked input data in db queries

But my app is built using reactjs and it auto escapes for me, so I'm protected from injection...right?

Yes it's true that react by default escapes all output when using {} in jsx so <,> and & are escaped, treated as string and not rendering as html. But there are some bypasses:
  1. there can be cases where you have to render content as html (e.g. user entered rich comments) and you need to use reacts dangerouslySetInnerHTML  which renders content as html and that is now a risk vector. If you have to use it then you need to sanitize the content passed to it. 
    • you must sanitize input on the server (because ui can be bypassed); libraries like sanitize-html-react can be used to do this on server and client if using dangerouslySetInnerHTML
  2. setting innerHTML on a dom element referenced using react createRef. Avoid that. Use innerText on a ref instead. Don't mutate the dome directly is good guidance.
Good post on this topic

Cross Site Request Forgery: this leverages 2 things 1. web apps store authenticated user session ids in cookies and 2. the default browser behavior is to submit all cookies in requests regardless of where the cookies originated.

Scenario: a hacker induces a user to perform an action they would not otherwise do e.g. change password, transfer money, expose information. The attack makes use of session cookies which already exist (because the user logged into their bank account 5 mins ago) and contain user authorization which are sent to the target site with the malicious request. How is the malicious request delivered? e.g. phishing emails, xss injecting malicious content into a trusted site.

The primary countermeasure involves using a csrf token generated on server which is sent back with each request. On receipt of a request,the server validates the csrf token exists and is valid to establish trust before allowing the action. It's critical the csrf is strong: the csrf token should be unpredictable and tied to the users session and strictly validated. csrf token is only necessary for change actions (not gets).

In addition cookies now have a "Same Site" cookie setting. By setting a session cookies Same Site you can restrict it to only be sent with same site requests (same-site:strict). This stops the default browser behavior of sending all cookies in requests and not include the cookie in requests that originate from another site. If set to Lax, then the browser will include the cookie in some cases only: GET requests and top level navigation e.g. link click (but not script originated requests). 

Its recommended to use both csrf and same site (defense in depth)





Open Web Application Security Project (OWASP) non profit is a good resource in general.


same origin: 2 urls are same origin if have same scheme (http/https) AND exact same host (www.example.com) and AND same port (443). 

  • www.example.com and example.com are not the same and considered cross origin
  • https://www.example.com:443/home and https://example.com:443/home are not same origin

same site: is less strict than same origin, 2 urls are same site if they both have same top level domain (tld) (e.g. .com, co.uk) and the domain before it e.g. for url  https://www.example.com:443/home the site is example.com

  • so scheme, port, and sub-domain can differ but still be same site

How to check? Chrome sends a Sec-FetchSite header with requests. You can check if it's same-site, same-origin or cross-site or none.


references

posrtswigger articles

web.dev/secure

Open Web Application Security Project (OWASP) non profit is a good resource in general.



Comments

Popular posts from this blog

deep dive into Material UI TextField built by mui

angular js protractor e2e cheatsheet

react-router v6.4+ loaders, actions, forms and more