I'm finishing a Cattle Drive assignment where a small Java web application manages a movie library for the client. The assignment is to put some security on the application using cookies, so that a "hacker" couldn't just guess one of the URLs that would lead to another part of the application. The user will be directed to login to the site and not be allowed to view other pages until logged in.
The parts of the web app are:
1. index.html
2. VideoServlet
3. listvideos.jsp
4. addvideo.jsp
5. videologin,jsp
The entry point is request URL http://localhost:8080/videos, which loads the index.html file. This page just has a link which redirects the user to the VideoServlet. From there, the servlet forwards the HTTP request and response to listvideos.jsp, which has a link to add videos if the users wants to do that.
I'm having trouble understanding how to implement the security using cookies, while keeping everything in the MVC2 pattern (the servlet is the controller, the jsp's are the view).
Here is the program flow I came up with, but I think I'm missing the point somewhere:
user enters URL http://localhost:8080/videos, which pulls the index.html file by default.
the index.html file basically sends an HTTP Get to VideoServlet. The servlet somehow knows the user isn't logged in yet, so forwards the request/response to the videologin.jsp.
a login is presented and asks the user for a password (this is a standard html form). The user enters the password and clicks submit. This sends an HTTP Post to the servlet.
the servlet checks the password and if correct, the user is logged in and the servlet forwards to listvideos.jsp.
I don't get where cookies come in or how they can help prevent a hacker from guessing a URL and gaining direct access to, for example, addvideos.jsp. Is a cookie being used to verify if the user has already logged in?
Cookies are some plain text values (stored in text files in browser cache normally) that you could use to store data on client side. When the user makes a request to a particular URL, all cookies stored on that server (domain) are passed with it, so that the server can read up those values.
In Java, you can set a cookie like this in your servlet (in your case, when user logs in, create a cookie and store a value in it (ex. username=josh). You could do this in your login servlet after a successful login.
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// Verify login, and get the username. Assume it's josh
Cookie cookie = new Cookie("username", "josh");
cookie.setMaxAge(60*60*24); // 24 hours for expiry
response.addCookie(cookie);
}
Later on, you can check for the existence of the cookie and if it exists, then the user has logged in. If not, you can send a redirect to the login page.
You can check for cookies like this in your servlet.
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Cookie[] cookies = request.getCookies();
String username = null;
for (Cookie c : cookies) {
if ("_username".equals(c.getName())) {
username = c.getValue();
break;
}
}
if (username == null) {
// Not Logged in. Redirect to Login
}
// User Logged In. Proceed
}
Instead of putting this code in all your Servlets + JSPs, you can easily put this into a Servlet Filter class. You can read up on more on that here: http://javaboutique.internet.com/tutorials/Servlet_Filters/
Ideally, you could provide a Logout feature also, which will remove the value assigned to the username cookie by replacing it with null.
I showed the above example because you mentioned that you need to use cookies for your assignment. But if you can, try to use the Sessions (which in turn uses cookies most of the time) to store logged in user details. With sessions, you can use session timeouts to ensure that idle users will be automatically logged off after a while and so on.
the index.html file basically sends an HTTP Get to VideoServlet. The servlet somehow knows the user isn't logged in yet, so forwards the request/response to the videologin.jsp.
The somehow knows is due to looking for the presence of the cookie in the request. Make sure the contents of the cookie are protected by a message authentication code, so you can be sure that your server actually handed out the cookie. It'd also be a good idea to encode into the cookie the specific IP address being used by the client, so an attacker can't hijack a cookie. (If a client changes IP address during a session, requiring them to log in again isn't horrible. Maybe annoying, but not unexpected.)
the servlet checks the password and if correct, the user is logged in and the servlet forwards to listvideos.jsp.
the user is logged in -- set the cookie into the browser for future requests.
Related
I've read the Tomcat CSRF protection fileter documentation and to my understanding the entry point must be pages that do not perform a security function.
I understand that when used any of the entry points are part of the nonce in the current session.
However as per the OWASP top 10 recommendations, I'm invalidating the session when a user logs in and generating a new session.
The issue I find is that when this is done, if a user clicks on a link that is only available once logged in, for example change password, which does not form part of the entry points a 403 is returned, due to the new session.
If the user clicks on one of the entry point urls first, they can then click on the change password link and access the page because a new nonce has been created and the change password link will be covered by this, but if the welcome page has other links that the user needs to use they cannot use the back button and click on the link(s) then as the nonce is not the same.
My question is how to handle the fact that when the new session is created the change password page will not be accessible without first clicking on one of the entry point urls.
I have looked at encoding the url, but it maybe my code is not written to handle this as correctly also I'm using JSTL due to its escaping properties to help prevent XSS and I can't seem to find a way to encode the urls with this.
Can anyone offer some advice or option as what would be best to do.
If it will help I'm including the login section of my controller servlet, which is reached via a login form post method.
public class UserController extends HttpServlet {
final static Logger log = LogManager.getLogger(UserController.class);
#Override
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
String requestURI = request.getRequestURI();
String url = "";
// Register a new user
if (requestURI.endsWith("/subscribeToSite")) {
url = subscribeToSite(request, response);
}
// Login
if(requestURI.endsWith("/logInToSite")){
url = logInToSite(request, response);
}
//try to login
User user = UserDB.loginUser(mPNum, upwd);
if(user==null){
url = "/loginerror.jsp";
}else{
HttpSession session = request.getSession();
session.invalidate();
session=request.getSession(true);
session.setAttribute("loggedUsrID", user.getUserID());
session.setAttribute("loggedUsrFName", user.getFName());
url="/schedule/welcome.jsp";
}
return url;
}//EO user login
OK worked around this by invalidating the session when logging in. Then creating the token off another page that is accessible only through the landing page.
I have IBM WAS 6.1 and Portal 6.1. Also i have a TAI which works when user login/logout in/out Portal. I want to work with HttpSession in TAI. Shortly my task is next: when user logging in i want to save some parameter in memory and as a key i want to use ID of HttpSession (or something else?).
For an example, while user logging id of httpsession is "foo". Than, user logged in and working in Portal, and press Logout button, portal logged out user using internal mechanize and than my TAI catch this request and now i have a http session with Id "bar". So, WAS changed http session. This means i can not user http session to save any parameter, because WAS recreates it for logging out. But i have to save some parameter while user logging in, and use it while he logging out.
Also i can't use Cookies for some reasons. Any idea how i can save ID based on HttpSession?
Or i have to know who(Portal Uid of user) pressed logout button in TAI. It is also helps me to resolve my problem.
UPDATE #1.
Also, for some reason WAS(?) delete custom cookie. I add custom cookie in TAI and WAS deleting it, i can not find my own cookie. Any idea where and why? There also http server beyond was and client, but i checked it - he shouldn't delete it.
I did not resolve question about http session, but i resolved problem with a cookie.
Right cookie:
Cookie cooky = new Cookie();
cooky.setPath("/");
cooky.setDomain("domain.com");
If a user goes on get_appointment.jsp but is redirected, by a servlet, to the login.jsp (as he was not logged in). After successful log in, he should return to the get_appointment.jsp, as the initialization was being done from there.
Now what machanism should be used to track that from which page the request originally came, may be got forwarded to different jsps and servlets and then the user should return to the original (initial page) again.
whats the most common and better way , in general rules. is there any one for the current senarios i explained? there are many, session attributes, url rewriting, global and application, servlet context.
what if user manually changes the address bar and goes to some other place. the session attribute then make him land some time later to some incorrect page.
whats a proper way?.................
for sessions. if iam in verfiycreds.java . is there a way to get the page addres from which the request was sent to verifycred.java (i.e login.jsp)?
You could save it in the user's session...
doGet(HttpServletRequest request, HttpServletResponse response) {
// Could also be doPost(), depending on which you need.
// Request and response are both abailable there as well.
...
HttpSession session = request.getSession();
session.setAttribute("referralURI", request.getRequestURI());
...
}
You can then retrieve the URI with request.getSession().getAttribute("referralURI").
If you want to avoid sessions, you could also pass the relevant portion of the URI as a get parameter to the login.
In spring-security, the request is saved at the point, where the request gets intercepted, because it is unauthorized - in the ExceptionTranslationFilter. After successful authentication, the success-handler SavedRequestAwareAuthenticationSuccessHandler/API will be called. This handler redirects to the URL of the request, previsouly stored in the HttpSession by the ExceptionTranslationFilter.
To answer your question, this is a proper way. Look at the way they implemented it, look at the patterns, check out the code.
I have implemented form authentication as offered by JAAS. Since I process all my pages as templates code has to be evaluated every time. Thus when the user is directo to /login the doGet request has to handle it and process the login template.
Now I would like to redirect to the main page after the login was successful. When the user chooses /login again he/she should be redirected to the main page.
Thus I need to know during a doGet request whether the user is authorized, maybe also which authentication. How can I check? Or is this idiom wrong?
Or is this done by request.isUserInRole(String role)? Since it does both, authentication AND authorization?
You can check if an user is logged in by checking if HttpServletRequest#getRemoteUser() (the user name) or #getUserPrincipal() (the associated Princpal object) does not return null.
So, e.g. in doGet() of the /login servlet you could do this:
if (request.getRemoteUser() != null) {
// Already logged in, so redirect to some main page.
response.sendRedirect(request.getContextPath() + "/main");
return;
}
// ...
The #isUserInRole() only checks if the logged-in user has some specific role and this is usually only useful to restrict some pages or page sections for specific roles. So unless you've a general role which is shared by every user, this isn't useful.
You may only want to add a message to inform the enduser why s/he is been redirected and what's the proper way to login again as another user. E.g. "You are already logged in. If you need to login as another user, please go to logout page first." or so in the main page which is conditionally displayed based on some redirect parameter.
I had a question about Java Servlets.
lets say I am on a servlet webpage, 'somePage'. I want to log in (using another servlet, 'login' servlet). So i click on the log-in link on the 'somePage' and get redirected to the 'login' page. I type in my name and password and they are both correct. the login page has successfully logged me in.
(now asking about coding for the 'login' servlet) How do I code the 'login' page so that it will redirect the successfully logged in person back to the, 'somePage' webpage?
Main Question: How does the login page know the page which initially redirected to it is the 'somePage' page?
I have checed out a lot of the request parameters, but non tell me, yes, you were directed from page, 'somePage'. These are the the paramater i have looked at:
String authType = request.getAuthType();
String pathInfo = request.getPathInfo();
String pathTranslated = request.getPathTranslated();
String getUserName = request.getRemoteUser();
String remoteAdd = request.getRemoteAddr();
String uriString = request.getRequestURI();
String sessionID = request.getRequestedSessionId();
String serverName = request.getServerName();
Integer serverPort = request.getServerPort();
String servletPath = request.getServletPath();
I know some of these are obvously not going to give me the answer I am looking for, but I figure one of the HttpServletRequest parameters has got to tell the login page who asked for it to be displayed. Any help would be greatly appreciated. I'm going to continue my search for the answer. I've tried to search for this question, but haven't found an answer.
Instead implementing yourself you should consider using form based authentification for your web app.
Almost every servlet container supports this.
At first you have to configure security. This depends on your application server. I.e. with Jetty you can use a database approach with tables for users and their roles or LDAP, etc.
In web.xml you turn on form based authentification:
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/logon.jsp</form-login-page>
<form-error-page>/logonError.jsp</form-error-page>
</form-login-config>
</login-config>
You specify two JSP pages you have to provide. logon.jsp is the login page for inserting user name and password. logonError.jsp is shown, if user name and password are invalid.
The whole login workflow is handled by the application server.
If the user first goes to a protected URL, the application server presents the login page instead. As a convention the input fields for user name and passwort should be named j_username and j_password. When the user submits the login form the server checks, if the user crendentials are valid (according to its configuration). If so the user is redirected to the original page. Otherwise the login error page is shown.
If you really want to implement it yourself then you can implement a servlet filter so that all calls to protected resources have to pass your filter.
In your filter you can check, if there is already a session present and if the user has successfully logged in. Then the normal call can proceed. Otherwise you can forward to your login page and store the original URL in the session. After a successfull login you can read the original URL out of your session context and redirect to the page the user wanted to see in the first place.
There are different ways of doing this. One way is to have your login page support a continue CGI parameter that gives the URL to which to redirect after the login is successful. Another way to do this is to use the "Referer" header that was passed to the login page, and redirect to that URL.
For the former, you can use ServletRequest.getParameterMap() to get the CGI arguments and determine if there is a CGI parameter named continue (or whatever name you choose to give to that CGI parameter); for the latter, you can use HttpServletRequest.getHeader() to get the "Referer" header.