1
\$\begingroup\$

I have to write a little social network for a case study at university. I have done some simple webapps before but nothing that required authentication, login and so on. So I wrote this little application after reading several guides on how this is usually implemented.

What I came up with is a simple login.html file in my server's public directory that contains a form with username and password. After submitting, the server looks up the username in a HashMap and checks firstly if the user exists and secondly if the password is correct. If both criteria are met, I set a cookie via response that contains a random UUID that the server keeps track of in an ArrayList. Lastly, the before filter checks if any protected page is being accessed, and if so, checks the requests cookies and looks them up in the ArrayList. If the cookie is known to the server I grant access to whatever is under /protected/.

Apart from encryption, is this code doing what I want? For me it looks like it works: login sets the cookie, logout removes it, /protected/ path can't be accessed without a known cookie. But I don't exactly know if I am missing something critical that might allow people to access pages without my knowledge.

package co.selim;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import spark.Spark;

public class Router {
    public static void main(String[] args) {
        Map<String, String> credentials = new HashMap<>();
        credentials.put("root", "passw0rd");

        List<String> tokens = new ArrayList<>();

        Spark.staticFileLocation("public");

        Spark.exception(Exception.class, (exception, request, response) -> {
            exception.printStackTrace();
        });

        Spark.before("/protected/*", (req, res) -> {
            if (!tokens.contains(req.cookie("token")))
                Spark.halt(401, "You can't access this page.");
        });

        Spark.post("/login", (req, res) -> {
            String username = req.queryParams("user");
            String password = req.queryParams("password");

            String storedPassword = credentials.get(username);
            if (storedPassword != null && password.equals(storedPassword)) {
                String token = UUID.randomUUID().toString();
                tokens.add(token);
                res.cookie("token", token, 3600);
            } else
                return "Username or password wrong.";
            return "";
        });

        Spark.get("/logout", (req, res) -> {
            String token = req.cookie("token");
            if (tokens.remove(token)) {
                res.removeCookie("token");
                return "Successfully logged out.";
            } else
                return "You were not logged in.";
        });

        Spark.get("/protected/controlPanel", (req, res) -> {
            return "<button>Launch nukes</button>";
        });
    }
}
\$\endgroup\$
  • \$\begingroup\$ No. Your token is not storing any information about the user, just a session ID. Your passwords are sent in query strings. This solution is vulnerable, at the very least, to Session Fixation attacks. There's no validation against the user either; I could create a cookie called "token" and your solution would consider me authenticated regardless of content of that cookie. I am hoping this is a proof of concept rather than something that is set to be used in a real production system. \$\endgroup\$ – Dan Pantry Jun 17 '16 at 10:38
  • \$\begingroup\$ I am checking whether the cookie called "token" was generated by the server: if (!tokens.contains(req.cookie("token"))) { ... }. So no, you can not just create a cookie called "token" and get access. However how would I be protected against Session Fixation? And is an attack really practical? \$\endgroup\$ – Selim Jun 17 '16 at 10:48
  • \$\begingroup\$ You're correct, I misread your code, you do check for that. Session fixation is corrected by following something like this where you change the session id every session. And no, it's not likely smoeone will attack your system on your PC, but it's important to instill correct security practices when you are writing systems that need to be, well, secured. \$\endgroup\$ – Dan Pantry Jun 17 '16 at 10:50
  • \$\begingroup\$ @DanPantry If I read the code right, I have to store the token in the cookie and in the session as well, so attackers can't just copy other peoples tokens, right? \$\endgroup\$ – Selim Jun 17 '16 at 11:15
1
\$\begingroup\$

I'm not familiar with Spark. It's obvious that this code isn't thread-safe (ArrayList isn't thread-safe, and tokens is accessed without any explicitly locking), but I don't know whether Spark provides the thread safety.

The cookie handling is missing two important parameters:

                res.cookie("token", token, 3600);

There are various overloads which take boolean secured, boolean httpOnly, and ideally you would set both of those to true. If you can't set secured because you're using a cheap web host which doesn't support HTTPS, at least set httpOnly.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.