Server side validation and sessions attribute in JSP Servlet [duplicate] - java

I have the requirement that the end user should not be able to go back to the restricted page after logout/sign out. But currently the end user is able to do that by the browser back button, visiting browser history or even by re-entering the URL in browser's address bar.
Basically, I want that the end user should not be able to access the restricted page in any way after sign out. How can I achieve this the best? Can I disable the back button with JavaScript?

You can and should not disable the browser back button or history. That's bad for user experience. There are JavaScript hacks, but they are not reliable and will also not work when the client has JS disabled.
Your concrete problem is that the requested page is been loaded from the browser cache instead of straight from the server. This is essentially harmless, but indeed confusing to the enduser, because s/he incorrectly thinks that it's really coming from the server.
You just need to instruct the browser to not cache all the restricted JSP pages (and thus not only the logout page/action itself!). This way the browser is forced to request the page from the server instead of from the cache and hence all login checks on the server will be executed. You can do this using a Filter which sets the necessary response headers in the doFilter() method:
#WebFilter
public class NoCacheFilter implements Filter {
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
response.setDateHeader("Expires", 0); // Proxies.
chain.doFilter(req, res);
}
// ...
}
Map this Filter on an url-pattern of interest, for example *.jsp.
#WebFilter("*.jsp")
Or if you want to put this restriction on secured pages only, then you should specify an URL pattern which covers all those secured pages. For example, when they are all in the folder /app, then you need to specify the URL pattern of /app/*.
#WebFilter("/app/*")
Even more, you can do this job in the same Filter as where you're checking the presence of the logged-in user.
Don't forget to clear browser cache before testing! ;)
See also:
Authentication filter and servlet for login
How to control web page caching, across all browsers?

*.jsp in Url Pattern won't work if you forward a page. Try to include your servlet too.. that will make your application secure from this back button problem.

The simplest way to do it without disabling the browser back buton is by adding this code to the page_load event for the page that you don't want the user to go back to after logging out:
if (!IsPostBack)
{
if (Session["userId"] == null)
{
Response.Redirect("Login.aspx");
}
else
{
Response.ClearHeaders();
Response.ClearContent();
Response.Clear();
Session.Abandon();
Session.Remove("\\w+");
Response.AddHeader("Cache-Control", "no-cache, no-store, max-age = 0, must-revalidate");
Response.AddHeader("Pragma", "no-cache");
Response.AddHeader("Expires", "0");
}
}

The correct way to do this is to add the
Vary: Cookie
header on secured pages. When the user logs out, clear their session cookie. Then, when they navigate back after logging out, the browser cache will miss. This also has the benefit of not completely defeating caching.

You can try telling the browser not to cache the homepage (using the appropriate headers - Expires, Cache-Control, Pragma). But it is not guaranteed to work. What you can do, is make an ajax call to the server on page load to check if the user is logged, and if not - redirect.

An alternative to implementing a Filter is to set a 'no-cache' filter on all the secured JSPs, or on all paths. This may be a good idea if the application is small, and if you would like to customize this property for a specific pages only. We can add the following Java snippet on every secured JSP that should not be cached:
<%
response.addHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setDateHeader("Expires", 0);
%>
If not on JSP, this could also be used in Controllers where routing is defined and set the headers for the 'HttpServletResponse' object.

For me the problem was , I didn't want to set headers on all pages , so I just set this header on page when logout is clicked and it clears everything related to the site :)
// Removes all site data
response.setHeader ("Clear-Site-Data", "\"cache\"");
Please read more about it over here :
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Clear-Site-Data

Related

how to disable back button- browser without using javascript i want to use servlet

I am facing problems in my application(built using JSP/servlet) when the user clicks browser's back button.How the servlet should be coded in such way that it detects browser's back button event and performs no action.I am not allowed to use Javascript.
Apparently the pages are been requested from the browser cache. You'll need to disable the client-side caching of the pages in question. You can do this by creating a Filter which listens on an url-pattern of the pages you'd like to disable the cache for, such as *.jsp. Do the following in the doFilter() method:
HttpServletResponse httpres = (HttpServletResponse) response;
httpres.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
httpres.setHeader("Pragma", "no-cache"); // HTTP 1.0.
httpres.setDateHeader("Expires", 0); // Proxies.
chain.doFilter(request, response);
Java Code will be executed on server side.
Javascript runs on client.
Its not possible to disable browser back button in Java, however you can choose what to do when such an event occurs. You can choose to show the same page.

Is there a solution to keep a cookie on browser while redirect the response?

I am building a user tracking system for a web application. People could came from many urls. I want to know from which urls the came from.
I design url like this : http://www.example.com/ref/XXXXXXX.
I create a Filter to handle incoming request :
String cookieKey = "examplesite.cookie";
String cookieValue = referralIdentifier;
Cookie cookie = new Cookie(cookieKey, cookieValue);
cookie.setMaxAge(60*60*24*365);
((HttpServletResponse) response).addCookie(cookie);
HttpServletResponse resp = (HttpServletResponse)response;
resp.addCookie(cookie);
resp.sendRedirect("/");
When this code execute, I cannot see the cookie set in the browser.
If I change the redirect to forward, I can see the cookie.
The I see this blog post how to track people with cookie and redirect where the blogger suggest to use code to redirect.
So I changed my code and I replace resp.sendRedirect("/"); by
resp.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
resp.setHeader("Location", "http://www.example.com/");
Here I can see the cookie in Firefox but not in Chrome.
Is there a solution to track user after redirection ?
According to http://www.javamex.com/tutorials/servlets/cookies_api.shtml by default a cookie is visible to "requests to subpaths of the parent from which the cookie was set".
This might be your problem. To make the cookie visible on all paths, you can set the path to "/" using cookie.setPath("/").

tracking page request with servlets and jsps

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.

Replacing or Deleteing a page in History

I am currently developing an app that has a login, after the person logs in I want to remove the login page from history so that if they choose the back button (after login) it wont go back to the login page, but the one before it.
In javascript the code is location.replace('whatever_url_you_are_forwarding_to'); I want to know the equivalent in Java / JSF
There is no way for server-side Java code to modify the history of the client-side browser.
I wouldn't mess with the browser history: users expect a consistent and predictable behavior for the back button. If they want to go back to the login page, let them go back to the login page.
You can solve this the following way:
Tell the browser to not cache the login page, so that it will always send a fullworthy GET request on it instead of loading from the browser cache.
When the login page is requested while the user is already logged-in, then send a redirect to the desired page (which you've remembered in the session when the user logs in).
This could be done in one and same filter (although I'd personally prefer to disable browser caching on all change-sensitive dynamic pages, so that would then be done in another filter on a more generic URL pattern covering those pages).
Here's a kickoff example assuming that you're using container managed authentication (for homegrown authentication wherein you manually put the user in the session, just check the presence of the session attribute instead):
#WebFilter("/login.xhtml")
public class LoginPageFilter implements Filter {
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession();
// Tell browser to not cache this page.
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
response.setDateHeader("Expires", 0); // Proxies.
// Check if user is logged in.
if (request.getRemoteUser() == null) {
// Not logged in, so remember previous URL and continue request.
session.setAttribute("referrer", request.getHeader("referer")); // Yes, the misspelling is "correct"!
chain.doFilter(request, response);
}
else {
// Logged in, so redirect to initial referring URL, if any.
String referrer = (String) session.getAttribute("referrer");
if (referrer != null) {
response.sendRedirect(referrer);
}
else {
// There was no referring page. Just continue request?
chain.doFilter(request, response);
}
}
}
// ...
}

How do I prevent browser caching with Play?

Part of my app provides a file to be downloaded using the redirect() method. I have found that Chrome (and not Firefox or IE, weirdly) is caching this file so that the same version gets downloaded even if it has changed server-side. I gather that there is a way to tell a browser not to cache a file, e.g. like this in the HTML, or by adding something to the HTTP header. I could probably figure those out in a lower-level web framework, but I don't know how to get at the header in Play!, and the HTML option won't work because it's not an HTML file.
It seems like there's always a clever and simple way to do common tasks in Play!, so is there a clever and simple way to prevent caching in a controller?
Thanks!
Edit:
Matt points me to the http.cacheControl setting, which controls caching for the entire site. While this would work, I have no problem with most of the site being cached, especially the CSS etc. If possible I'd like to control caching for one URL at a time (the one pointing to the downloading file in this case). It's not exactly going to be a high-traffic site, so this is just academic interest talking.
Ideally, I'd like to do something like:
public static void downloadFile(String url) {
response.setCaching(false); // This is the method I'm looking for
redirect(url); // Send the response
}
Play framework response object has a setHeader method. You can add the headers you want like this, for example:
response.setHeader("Cache-Control", "no-cache");
I haven't tested it, but it looks like the http.cacheControl configuration setting might work.
http.cacheControl
HTTP Response headers control for static files: sets the default max-age in seconds, telling the user’s browser how long it should cache the page. This is only read in prod mode, in dev mode the cache is disabled. For example, to send no-cache:
http.cacheControl=0
Default: 3600 – set cache expiry to one hour.
It is actually this:
response().setHeader("Cache-Control", "no-cache");
Tommi's answer is ok, but to make sure it works in every browser, use:
response().setHeader("Cache-Control", "no-cache, max-age=0, must-revalidate, no-store");
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate, pre-check=0, post-check=0, max-age=0, s-maxage=0"); // HTTP 1.1.
On play currently 2.5.x to 2.8.x
you can set cache life of both assets folder or assets file in configuration.
For folder-
play.assets.cache."/public/stylesheets/"="max-age=100"
play.assets.cache."/public/javascripts/"="max-age=200"
for specific file -
play.assets.cache."/public/stylesheets/bootstrap.min.css"="max-age=3600"
--- documentation
https://www.playframework.com/documentation/2.8.x/AssetsOverview

Categories