Circumventing the login-page breadcrumb security breach
-
Hi All,
As reported here: https://community.nodebb.org/topic/12013/securing-nodebb-with-a-ssl-aws-linux2-letsencrypt-nginx-exploits
I wanted to make the forum private (no guests). Did everything listed here: https://community.nodebb.org/topic/2371/faq-how-to-make-your-forum-private and included JS that checks if the UUID==0 and kicks the user to the login page.
Unfortunately, the login page incorporates breadcrumb (I did not find anything in the ACP that allows removal thereof). Clicking home, loaded the home page from the cache (if existed). From the home page, all the site may be browsed even-though the user was logged out.
See for yourself - try to log out and in the login page simply press "home" on the breadcrumb
Anyway it took some time, but I figured out how to fix this.
- Create a customized welcome page
- Create links in the welcome page to the site (into categories etc.).
The customized page will not have breadcrumb (that's good news).
Now for the fun part (hack hack hack):
The href string should take the following form:
<a onclick="window.location='/categories?t=' + Date.now();return false;" href="#">name of link</a>A click on the link will generate a new href string that will not exist in the cache. The server will invalidate the request (returning the proper UUID=0) and the client will revert the user back to the login page.
Now, during my hacking I did find that the UUID is basically a counter. That is the UUID is not hashed. That's not promising...
Will dig in further...Have fun!
JJ. -
The solution presented in my previous post is merely a bandage.
Now coming to theproblem, I believe nodebb is storing the user credentials in scoped variable. When the logout event occurs the values are not removed from these scoped variables.
@julian, @PitaJ , may I humbly suggest the following:
- Remove breadcrumbs from the login page
- Refrain from exposure of the UUID to the user (it should be kept at server-side). Each page should call a JS function on the server to validate access. A cookie is sent to the server and together with collected credentials for validity.
- Invalidate scoped variables in the cache upon layout (or portion thereof).
- Enhancement - hash the UUID.
I believe #4 is perhaps the most important issue of them all. From what I have seen, the current UUID implementation uses a running counter starting from 1. It does not take a lot to figure out the UUID of the admin (first user ). Hash helps distancing the user apart.
I realize that you need a quick way to handle the posts UUIDs, and using the RFC compliant UUID string is an issue. To that end, please see how twitter resolved its uuid issue: https://blog.twitter.com/engineering/en_us/a/2010/announcing-snowflake.html (code is in github).
Again, awesome work guys!
I hope this helps,
JJ. -
There's no login page security breach. You can make it so only logged in users can view all categories by changing the permissions for guests. There's no reason to restrict people from accessing your home page if you have the privileges set up correctly.
If you really want people to access nothing before logging in, then you should be creating a plugin which checks if someone is logged in, and if not, redirect them to the login page.
-
@pitaj said in Circumventing the login-page breadcrumb security breach:
There's no login page security breach. You can make it so only logged in users can view all categories by changing the permissions for guests. There's no reason to restrict people from accessing your home page if you have the privileges set up correctly.
Thank you @pitaj. Believe me the privileges are set properly (to restrict). JS code that tests the UUID is there as well. The issue stems from a breadcrumb in the login page exposing cached pages. Plugin code won't help as scoped variables are cached and not cleaned after login.
Kindly test this yourself - the issue is easily reproducible. Use the out of the box code, restrict access in ACP, add the JS code that checks for UUID and reverts the user to the login page if uuid==0. Then, log-out, and follow the breadcrumb in the login page. As long as pages are not refreshed from the server, the site will be exposed.
Let me know if you are able to reproduce, I'll try to help out from here.
Thanks again!
JJ. -
@jjsagan so what you're saying is that if you change the privileges after a user has accessed your site, the user can see the categories still?
Of course if someone has accessed your site before you change the privileges, they will have some information about it. There's no way to prevent this.
But a user shouldn't be able to see any up to date information. They won't be able to access topics or categories. All of that information is provided by the server.
I'm struggling to understand what you're talking about, it sounds like an enormous edge case.
-
Hi @pitaj good morning.
Kindly follow the below:- Disable access to all unregistered users.
- Add a global JS script with:
$(window).on('action:ajaxify.end', function() {
if (!app.user.uid ) && ajaxify.currentPage !== 'login') {
ajaxify.go('login');
}
});
$(document).ready(function(event, data) {
if (!app.user.uid ) && ajaxify.currentPage !== 'login') {
ajaxify.go('login');
}
});Log out of your account. In the login screen press "home" on the breadcrumb.
Since the uuid is probably scoped, you are allowed to go into categories, and from there anywhere as long as the pages are cached.
Sometimes, the categories are hidden and the page is blank, sometimes they are not.
The expected behavior: unregistered user must stay in the login screen even if all other pages are scoped.
Thank you very much for looking into this. Highly appreciated!
JJ.