All of the solutions (use of tokens, for example) I have seen so far detail how to prevent a CSRF from an external website i.e. prevent a CSRF from evil.com to victim.com. However, how would one protect from a CSRF from within the same site i.e. someone posts a link on victim.com that forces anyone who clicks on it to delete their victim.com account?
Well, the CS in CSRF stands for cross site.
But generally, the attack scenario you describe should not be possible for two reasons:
- GET requests should not change server-state, so they do not need any CSRF protection.
- Requests that do change server-state should be protected via a token. This token should not automatically be added to user-supplied data, and an attacker cannot create a link or form containing this token, so even requests from the same site will be blocked.
If you use a referer-based approach to CSRF protection (or if you automatically add a token to all links or forms), and if GET requests change server-state (or if POST requests can be converted to GET requests, or if you allow the user to post form tags) you should:
- Strongly consider your approach in general. You are not following best-practices regarding security or web development.
- Not allow users to post excessive HTML. Especially
formtags which are needed for POST CSRF should not be permitted, as they allow a number of other attacks (stealing of secret information, phishing, etc).
CSRF protection tokens need to be user-specific. I can create a request that deletes my account (or whatever) by including my token, but I don't have the token for anybody else so my forged request, if sent with somebody else's session ID cookie, would fail (be blocked by CSRF protection).
It sounds like you missed at least one critical element of CSRF protection. Either you misunderstood that the anti-CSRF tokens must be unique per-user, or you're trying to use some sort of request-origin filtering thing (like Referer or Origin headers) to detect CSRF, and that is the wrong way to do it.
It doesn't really make a difference whether a malicious link or form is in a page on the same domain or a different domain.
When you require the request to contain a security token that is only valid for a very specific situation, an attacker will not be able to guess that token even when smuggling a link into content on the same domain.
Additionally, any activities that modify data should not be allowed to be triggered by a GET request. Always require POST, additionally requiring a security token that is connected to the currently logged in user and cannot be reused in different situations.