How is it possible to check if a tomcat session is valid by knowing only the sessionid?
I want to create a REST endpoint that checks if a session is valid by passing it just the sessionId. The session cookie is not available in this request.
You can use the HttpServletRequest#isRequestedSessionIdValid method to check whether the request session is valid or not:
#GET
public Response someMethod(#Context HttpServletRequest request) {
System.out.print(request.isRequestedSessionIdValid());
}
Related
I am having difficulty to store cookies in a React Native apps.
My goal is to send the JSESSIONID and XSRF-TOKEN as Response Header's keys instead of Set-Cookie, and the client will handle to store it as cookie manually.
I will store the JSESSIONID as cookie with HttpOnly set to true.
I will store the XSRF-TOKEN as cookie with HttpOnly set to false.
Basic Security Concepts:
1. Session Cookie (JSESSIONID for example).
Should always be HttpOnly, have a domain set (or use the default as the server that provided it).
Never be stored anywhere other than the browser handling it. Your JS/HTML should know nothing about the JSESSION Cookie and only just move the user to a login screen if they get a 401 (UnAuthorised) from an endpoint.
2. CSRF Tokens.
Back in the day (5 years a go probably ha!), most sites were rendered on the server. The server created the HTML and then just sent it back via the URI. Like you went to /profile then the server knew who you were and then created the profile page on its server and just fed back the HTML document.
When wanting to get some user input, this HTML rendered by the server would contain a <form/> which would collect user's data (password/bank details etc.) and then with the onSubmit passes it back to the server in a application/x-www-form-urlencoded format
eg.
https://thewebsite.com/sendmoney_to?account=512&amount=1milliondollars
By simply sending that link to someone who has an active session with the site thewebsite.com the browser would visit it and carry out the request.
The victim is logged in as far as the site is concerned and will happily run that request sent by the attacker. These links were at one point even follower by simply loading an <img> like by posting on their wall or in an email etc.
So how did they fix this?
By adding some fields to the form called hidden fields. These hidden fields are created by the server when the page is rendered. They contain a value that is the CSRF TOKEN and also something in a CSRF COOKIE. So when the application/x-www-form-urlencoded form is sent, it must have these values produced on the server when rendering the form. The server can then verify the form was the one they created and not some malicious link an attacker created.
An attacker can not know/guess these when making their naughty link.
3. Nower Days
With having only JSON requests as many sites, like React Apps, are rendered client side and use Axios/Fetch...CSRF is somewhat redundant. You don't post forms/application/x-www-form-urlencoded...only make POST requests with a JSON body.
Sessions are still important as an XSS attack > CSRF attack. Store the session properly (JWT token or not...don't jump on the JWT band wagon and start throwing that JWT Auth Token around Local Storage which seems to have become some kinda strange default for newer devs).
If you are sure you only have application/json capable endpoints, then the only way an attacker is going to get you to POST their content instead of what you are meant to is via an XSS attack. But once they have an XSS attack it is game over anyway. They are simply then you as far as the server is concerned as they use their naughty injected <script> to manipulate the request before it sent and the server would have no way of knowing it had been manipulated on the fly (usually).
4. Getting your CSRF Token via a Header as it wont be made in the form
The XSRF-TOKEN you may need to expose the XSRF token by using a filter that will extract the CSRF Token (via the session) and adds it to a header on the response entity.
I wrote my own but it is basically the same in a library some use to do this same thing.
#Log4j2
public class CsrfBindingFilter extends OncePerRequestFilter {
protected static final String REQUEST_ATTRIBUTE_NAME = "_csrf";
protected static final String RESPONSE_HEADER_NAME = "X-CSRF-HEADER";
protected static final String RESPONSE_PARAM_NAME = "X-CSRF-PARAM";
protected static final String RESPONSE_TOKEN_NAME = "X-CSRF-TOKEN";
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, javax.servlet.FilterChain filterChain) throws ServletException, IOException {
CsrfToken csrfToken = (CsrfToken) request.getAttribute(REQUEST_ATTRIBUTE_NAME);
log.debug("CRSF Token from session : {}", csrfToken != null ? csrfToken.getToken() : "CsrfToken is NULL");
if (csrfToken != null) {
response.setHeader(RESPONSE_HEADER_NAME, csrfToken.getHeaderName());
response.setHeader(RESPONSE_PARAM_NAME, csrfToken.getParameterName());
response.setHeader(RESPONSE_TOKEN_NAME, csrfToken.getToken());
}
filterChain.doFilter(request, response);
}
}
As far as the session, the browser should handle that and you should not be messing with it client side unless it is for a very specific reason (and I can't fathom one). The Cookies for Sessions are set as HttpOnly for the specific reason to disallow any JS running in the client to edit/read/add it.
One little cheeky advert/xss with some naughty code like get the cookie called JSESSION ID if the host is myvictim.com and post it over here... could mean you are compromised.
Read this for more detail:
Add HttpOnly Cookie via JS
The browser should handle the Set-Cookie headers as intended and is best practice (out of security reasons and also just for plain simple ease of use).
WebSocket STOMP Authentication
Once a user has been authenticated via your /login, Spring should send a Set-Cookie header with the JSESSIONID Cookie. This cookie will be stored by the browser and should be inaccessible to your front end javascript app.
If you then use the STOMP Spring WebSocket implementation, you can get the principal user name from a STOMP message by getting it via the StompHeaderAccessor in the #MessageMapping Controller params.
stompHeaderAccessor.getUser().getName() would give the Spring Security authenticated user's principal name (usually their username or id, username is default).
#MessageMapping("/agents/start")
public void start(StompHeaderAccessor stompHeaderAccessor) {
log.info("Subscriber Start! {}-{}", stompHeaderAccessor.getUser() != null ? stompHeaderAccessor.getUser().getName() : "ANON", stompHeaderAccessor.getSessionId());
mysessionstore.addSessionId(stompHeaderAccessor.getSessionId());
}
If you then want to edit the user's session attributes, you will then need to fetch their session id from the SPRING_SESSION table and you can use the Spring SessionRepository to fetch it.
https://docs.spring.io/spring-session/docs/current/api/org/springframework/session/SessionRepository.html
I'm implementing spring security in my project and have used mysql database to store sessions. Everything works fine but when the user logs out, its session is also deleted from the database which I do not want. I only want session to be invalidated but not deleted from the database.
On debugging, I found :
public void logout(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) {
Assert.notNull(request, "HttpServletRequest required");
if (invalidateHttpSession) {
HttpSession session = request.getSession(false);
if (session != null) {
logger.debug("Invalidating session: " + session.getId());
**session.invalidate();**
}
}
if (clearAuthentication) {
SecurityContext context = SecurityContextHolder.getContext();
context.setAuthentication(null);
}
SecurityContextHolder.clearContext();
}
This code is from SecurityContextLogoutHandler class.
Further, the code execution goes in:
private final class HttpSessionWrapper extends HttpSessionAdapter<S> {
HttpSessionWrapper(S session, ServletContext servletContext) {
super(session, servletContext);
}
#Override
public void invalidate() {
super.invalidate();
SessionRepositoryRequestWrapper.this.requestedSessionInvalidated = true;
setCurrentSession(null);
clearRequestedSessionCache();
**SessionRepositoryFilter.this.sessionRepository.deleteById(getId());**
}
}
The last line of the function deletes the session which I do not want.
My question is can I stop spring security from deleting sessions from the DB when user logs out or this is how spring security works?
Is there any specific reason why you don't want to delete session from DB once user log's out ? This is pretty much common behavior. Session is representing your logged in client. Once client log's in (provide valid credentials, password with username for example) session ID is created and sent to client. This session ID is representing valid logged in connection. On subsequent request's from this client he will only send this session ID inside header, your app will check if this session ID is stored inside valid session's (your DB for example) and if it is this request is considered authenticated (therefore client doesn't have to send his credential's which has to be verified with each request, he is only sending session ID). Once client log's out the session ID is invalidated since with logout his connection is no longer authenticated. Therefore yes this is how spring security work's, there is no need to persist invalidated session's. You would also have to implement custom mechanism for clearing session's from DB (when will be session cleared if not at time of user logout). Also you might consider to use session pool inside memory instead of DB.
Edit: i don't how spring check's valid session's in case of DB session pool but at some time it has to access DB read all session's so it can find out which session ID's are valid (i guess this is done for each after - login request at least). How could be invalidated session in your case be persisted inside database session pool when valid session's are defined by that pool at same time ?
I have developed a web app currently hosted in tomcat 8.5.I5. I am trying to implement SSO with IDP and here I have used filters for this. After sucessful login I set the user name as following.
HttpSession httpSession = request.getSession();
httpSession.setAttribute(SESSION_USERNAME, subject);
When validating used the following code.
HttpServletRequest request = (HttpServletRequest) req;
HttpSession session = request.getSession();
String userName = (String) session.getAttribute(SSOHelper.SESSION_USERNAME);
if (userName == null && request.getRequestURI().contains("dashboard.xhtml")) {
Logout is implemented as follwing
request.getSession().invalidate();
The problem is this only works for the first time. Second time it keeps on asking the login. Seems the session is created per requested.
The issues seems to be when you define the host name without a dot (.). For example I have used localhost for my testing. After adding a entry to hosts file with domain name malaka.com, and used to access the web app, issue was resolved.
I have configured AuthFeature with CustomUserSession and use RedisCache as User Auth Repository. And then I use C# JSON service client to authenticate service, authen OK but session ID store in cache does not same as cookie value.
Cookie: ss-id => I0ZIuzLijch3IY9Tut0z
Cache: urn:iauthsession:brSXBQPjmIB6Srv6EPCv
Please help !
Update ...
Below code use JsonServiceClient: using (var client = new JsonServiceClient("https://api.futabus.vn/api"))
{
var lRes = client.Post("/auth/credentials", new
{
UserName = user.UserName,
Password = user.Password
});
}
BUT when i post direct to https://api.futabus.vn/api/auth/credentials then cookie value same as session id in response object and in cache.
This contains nowhere near enough info to identify the issue, you should at a minimum show the HTTP Headers and code used to make the request.
But the session key is derived from the sessionId if it's not using ss-id then you're likely authenticating with RememberMe=true in which case ServiceStack stores the User Session against the ss-pid Cookie instead. If it's not then double-check the HTTP Headers as the Cookie you think is being sent is likely not the one being sent.
I have 3 applications:
1. Main website: example.com
2. User website: id.example.com
3. API: api.example.com. All cookies restrict to the first (1) website (root domain)
All websites have been written with ServiceStack Framework 4.0.
When i call Authentication from the second (2) to api.example.com using JsonServiceClient then:
the cookies store in the first (1) and cookies i get as soon as call authentication are different.
I think cookies store in the first (1) have been encrypted.
The first (1) using Form Authentication with machine key settings in web.config
Anyone else have idea?
A HTML5 UI is connected to the backend (REST Jersey to business logic to Hibernate and DB). I need to create and maintain a session for each user login until the user logs out.
I am clueless on how to approach this problem.
I followed this approach
Initially when the User is successfully logs in , i am setting attribute under session as shown below
HttpSession session = request.getSession(true);
session.setAttribute("islogged", "islogged");
String value = (String)session.getAttribute("islogged");
System.out.println("****************** The User Logge in Value"+value);
Later in a different page i am checking if the user is logged in or not this way
public String checkIfUserLoggedIn() throws JSONException,ClassNotFoundException, SQLException
{
HttpSession session = request.getSession();
String value = (String)session.getAttribute("islogged");
if(value==null)
{
// always its coming here only
}
}
I agree with francesco foresti, please do not rely on HTTP session without Auth. this is unsafe, and quite dangerous for your app.
Have you been implementing a specific session mecanism ?
If not, jersey as it is will not store session data as it. Every call that you will make will give you a session id that is different from yours.
You have to make authentication & use the auth token in order to identify you session.
use JAX-RS
Please do use an auth mecanism as defined : https://jersey.java.net/documentation/latest/security.html
#Path("authentication")
#Singleton
public static class MyResource {
// Jersey will inject proxy of Security Context
#Context
SecurityContext securityContext;
#GET
public String getUserPrincipal() {
return securityContext.getUserPrincipal().getName();
}
}
or use another framework : Spring, Shiro.... etc.
I really prefer that solution, since another framework will implement a lot of stuff for you. You gain a lot of time doing so.
Please take a look to official jersey doc: https://jersey.java.net/documentation/latest/index.html
I wouldn't rely on the http session. My approach would be to put an "Authorization" field in the header of the response that the server returns when the user logs in, and ask the user to put the very same header in each suqsequent call. In this header you put the informations that help the server find the identity of the user
(take a look at what twitter does as an example : https://dev.twitter.com/oauth/overview/authorizing-requests). The server could save the informations about the logged in user in the database, or You could create a Map in a Singleton that would serve as the "authorization gatekeeper" for your services.