In the world of web development, there's a classic problem: how to protect users from attacks they commit themselves without even realizing it. This is called CSRF (Cross-Site Request Forgery).
Most systems solve this problem in the standard way: they issue each user a secret code (token) and force them to present it for every action. But at RK-CMS, we took a different approach. We simply hid the doors themselves.
Let's look at how this works and why storing "keys" in cookies isn't always a good idea.
Classic Problem: You Bring the Burglar the Key
Imagine a classic online store. User Vasya has logged in. The server has given his browser a "pass" (session cookie) so Vasya doesn't have to re-enter his password on every page.
Now imagine Vasya has visited a malicious website. This page contains hidden JavaScript code that attempts to send a request to an online store. For example, "transfer all funds to the hacker's account."
Vasya's browser sees a request to a familiar site and automatically inserts Vasya's "password" from the cookies. The store's server sees that the request came with the correct password. That means it was Vasya. The money is gone.
What's the attack all about? The browser doesn't realize that the command wasn't issued by Vasya, but by malicious code on another site. Vasya has become a puppet.
Standard solution: CSRF token (Password for every action).
To distinguish the "real Vasya" from the "puppeteer," developers came up with CSRF tokens.
It works like this:
Vasya goes to the money transfer page.
The server generates a secret set of characters (a token) and embeds it directly into the page's HTML code (in a hidden form field).
Vasya clicks the "Translate" button.
The request is sent along with this token.
The malicious site can't read this token (due to browser policy), so its request will be rejected.
But there's a catch: Developers often store this token in a cookie for convenience.
Here lies the trap we're talking about.
Why is storing the CSRF token in a cookie a bad idea?
If we store the security key in a cookie, we're back to square one.
The malicious site sends the request.
The browser automatically appends all cookies for this domain to the request—both the session and your CSRF token.
The server looks and says, "Aha, the session is there, and the CSRF token is there. Everything matches!"
The attack is successful.
Conclusion: A CSRF token in a cookie is like putting the key to a safe under the doormat right next to the door. Technically, there's a lock, but it's of no use. In this case, the token simply replicates the session path and doesn't prove that the action was performed by the person who clicked the mouse, not a script.
Messenger Scenario: Why SameSite=Lax Doesn't Save You
Many people now say, "We store the CSRF token in a cookie, but set SameSite=Lax so that the cookie won't be lost with POST requests." This is true, but there's a loophole.
Imagine: an attacker sends you a message on Telegram or WhatsApp: "Look at this funny picture!" and attaches a link. But the link doesn't point to the picture, but to an address in the admin panel that performs the action via a GET request. For example:
https://site.com/admin/transfer?to=hacker&amount=1000
You click the link, and the browser opens it as a normal link. SameSite=Lax allows sending navigation cookies (GET). As a result, the browser will attach all cookies to the request, including the session cookie and, if present, the CSRF token. The server will see a valid session and a valid token (since they both came from cookies) and perform the transfer. You won't even understand what happened; you'll only see an error page or a blank page, and the money has already been sent.
This is the danger: if an action can be performed via GET, SameSite=Lax won't help because it allows GET requests. Storing the CSRF token in a cookie makes the attack even easier: the attacker doesn't even need to guess or steal the token; it will arrive with the request.
In RK-CMS, such an attack is impossible because the action URL contains a secret prefix. An attacker can't guess this prefix, and without it, the server will return a 404 response. Even if they trick the user into clicking the link, it will be broken. That's why we don't rely on cookies or SameSite, but instead make the URLs themselves unpredictable.
RK-CMS Approach: Every Door Has Its Own Address (Unique URL)
In RK-CMS, we decided to abandon the pursuit of tokens and "secret words." We use dynamic routing with a secret prefix.
How does this work in practice?
In a typical CMS, a link to delete an article looks like this:
/admin/posts/delete/123
Everyone knows this address. The hacker only has to trick the victim's browser into clicking it.
In RK-CMS, things are different. For each user within their session, we generate a unique secret prefix.
The link looks something like this:
/aB3xZ9qL/admin/posts/delete/123
And for another user (or in another session), it would be:
/Kd8sNf2p/admin/posts/delete/123
Why does this work?
UnknownAddresses (Security through Obscurity in a good way):
The attacker doesn't know the exact secret prefix assigned to the current session of user Vasya. They may know to delete post 123, but they don't know the full URL.
Previously: They could send a request to /admin/posts/delete/123.
Now: They'll send a request to this address and receive a 404 Not Found response because the correct address contains the secret key.
A cookie won't help here:
A hacker can't extract this prefix from a cookie because we don't put it there on purpose. The prefix exists only in the page's HTML code, which the hacker can't read.
Clickjacking Protection:
A common attack involves placing a transparent iframe over a legitimate website, tricking the user into thinking they're clicking the "Win a Prize" button, but actually clicking the "Delete Account" button.
In our case, even if an attacker loads our website in an iframe, they won't be able to guess the URL with the secret prefix to load the desired page with the dangerous button.
Result: Simpler, but more secure.
RK-CMS's approach breaks the mold. Instead of adding an additional entity (a token) to the system and monitoring its synchronization, we made the address system itself unpredictable.
We don't give the user a "card" that can be stolen from their browser (a cookie). We simply give them the coordinates of a secret door, which only they know at that moment.
Pros of this approach:
No false sense of security: We don't fake security by storing keys in a publicly accessible location (in cookies).
Ease of implementation: No need to generate, validate, and store millions of tokens for each form.
Reliability: A hacker cannot physically forge a request because they don't know the destination.
At RK-CMS, we believe that security should be pragmatic.