In short - I would like to add such service endpoints to my servlet that can only be called from localhost. The restriction should be coded in the servlet itself, i.e it should not depend on Tomcat/Apache to be configured in a certain way. At the same time, there are many other, existing endpoints that should be reachable externally.
Longer description - I am creating an HTTP API that 3rd parties can implement to integrate with my application. I am also supplying a default implementation, bundled together with my app, that customers with simple requirements can use, without having to implement anything.
The endpoints of my default implementation should be reachable only for my app, which happens to be the same servlet as the one supplying the implementation, i.e it runs on the same host. So for security reasons (the API is security related), I want my implementation to be usable only for my app, which in the first round means restricting access to localhost for a set of HTTP endpoints.
At the same time, I don't want to rely on customers setting up their container/proxy properly, but do the restriction in my servlet, so that there are no changes required for existing installations.
So far the only idea I had was to check the requestor's IP addess in a servlet filter - so I am wondering if there is a better, more sophisticated way.
I think you should add Web Filter to your application and check your url in doFilter method. Check request.getRemoteAddr() and endpoint link you can put in urlPattern.
Like this:
#WebFilter(urlPatterns = "/*")
public class RequestDefaultFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
if (isForbidden(request, response))
return;
else
chain.doFilter(request, response);
}
}
isForbidden implementation is up to you. In response you just send 403 error code for example.
You can check make same check in servlet and send in response 403 error.
Related
We have a embedded Jetty 10.0.12 server, configure everything programmably (no web.xml) and already have a few servlets registered. We want to add a new servlet for an internal API. I have already done this. We now want to secure it. Security would be pretty simple: if the request did not come from within the server, reject it. This is good enough because we employ other security standards in the other servlets. I know where to start: create and register a filter:
public class InternalFilter implements Filter {
#Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
// TODO: Check if request is internal.
// I.e., came from another registered servlet in the same JVM.
// If it is internal, then `chain.doFilter`.
}
}
I do not know how to proceed from here.
I'll start by assuming that "internal" means you are using either RequestDispatcher.include() or RequestDispatcher.forward().
If so, then you can check the HttpServletRequest.getDispatcherType() value.
Value
Meaning
DispatcherType.FORWARD
Request arrived from a call to RequestDispatcher.forward().
DispatcherType.INCLUDE
Request arrived from a call to RequestDispatcher.include().
DispatcherType.REQUEST
Request arrived from the beginning of the server handling tree.
DispatcherType.ASYNC
Request arrived from call to HttpServletRequest.startAsync()
DispatcherType.ERROR
Request arrived from error handling (either an unhandled exception, or from a call to HttpServletResponse.sendError()
How can i create a full web application with Java and React without having to create a rest API, not even a private API with username:password authentication.
I want it to be as it is created with JSP.
Is it possible call Java methods with react locally ?
Or even creating a restfull API that can only be called locally
Thank you
I don't think it's possible to communicate with Java in a client library such as React without having to create a HTTP API.
But you could make one and add a bit of extra layer of security to ensure that only your application could call your Java API by checking the remote address of each call and verifying that's the caller is indeed your server.
You can do this in Java using the getRemoteAddr() method from the HttpServletRequest object.
The best way to do this is to create a filter class that map all the API links and verify the remote address in each calls and then decide if it should allow it or not.
Here's an example:
import javax.servlet.*;
public class RequestFilter implements Filter{
public void init(FilterConfig config) throws ServletException {}
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)req;
String callerIp = request.getRemoteAddr();
if(callerIp.equalsIgnoreCase("MY-SERVER-IP-ADDRESS")) {
chain.doFilter(req, res);
}
else {
((HttpServletResponse)res).sendError(HttpServletResponse.SC_FORBIDDEN, "Access denied !");
return;
}
}
public void destroy() {}
}
Replace "MY-SERVER-IP-ADDRESS" with your server ip.
And to map all the calls, set the filter tag in your web.xml as follows:
<filter>
<filter-name>RequestFilter</filter-name>
<filter-class>com.myPackage.requestFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>RequestFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
This should satisfy your need, but if you found another way please share it with us.
the first request is no, as far as I'm aware. But as for the local rest api, I know most web servers can check CORS headers and restrict to only serve certain origins on answering requests. So whichever JRE Web Server you're using, check it's API for accessing the origin in the request header, and route those to the rest code.
Lets say I have a simple "Hello world" type servlet, configured with the annotation #WebServlet("/hello").
I want to disable it for build/deployment, so it will not be possible to "call" the servlet. How would I do that?
Then, through a configuration file, I want to be able to enable the servlet at run-time, so it can be used by a client. How would I do that?
Is either of these possible?
You can't enable servlets during runtime via standard API. It can at most only be enabled during build time in web.xml or during deploy time by ServletContext#addServlet(). Your best bet is to always enable it and control it on a per-request basis. You can use a servlet filter for this.
First give the servlet a name.
#WebServlet(urlPatterns="/hello", name="yourServlet")
public class YourServlet extends HttpServlet {
// ...
}
So that you can easily map a filter directly to it without worrying about servlet's URL patterns.
#WebFilter(servletNames="yourServlet")
public class YourFilter implements Filter {
// ...
}
In your filter, just decide whether to continue the chain, or to return a 404 based on your configuration file setting.
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if (isYourConfigurationFileSettingSet()) {
chain.doFilter(request, response);
} else {
((HttpServletResponse) response).sendError(HttpServletResponse.SC_NOT_FOUND);
}
}
The isYourConfigurationFileSettingSet() part can't be answered in detail based on the information provided so far. In case you actually also couldn't figure out that, then head to Where to place and how to read configuration resource files in servlet based application?
Instead of defining the servlet through an annotation, do it in the web.xml file. Different versions of this file may allow you to have the servlets enabled or not.
The version of web.xml to use should be selected at build and deployment time. Maybe by a Maven profile or similar. Take a look at the following link for some ideas on that: https://maven.apache.org/guides/mini/guide-building-for-different-environments.html
If you want truly run-time control, then you may have to do a little custom coding. A filter (or, I suppose, the servlet itself) could check the value of a property and return a response with an HTTP error code (I suppose 403 would be vaguely appropriate; 404 less so, but if you want it to appear as though the servlet didn't exist in that configuration, it would work...)
We want to implement a public RESTful API integrated in our software (written in java) that might be used by various clients to build small e-commerce apps (e.g. for Android or iPhone). This API includes getting a list of products, categories, shopping cart support, etc.
We need to provide an API that will allow user registration and couple of other sensitive functions. How should we protect this API against spam and bruteforcing? In the standard product we use reCAPTCHA. Any alternative for the REST counterpart?
First, think of separation of concerns. What is the purpose of REST API?
A REST API should do offer a service to the client. Client sends a request via REST protocol, and gets a response for its request. In code, this looks something like:
#GET
public Response getClientInfo(#QueryParam("clientId") Integer clientId) {
ClientDTO clientDTO = database.getClientInfo(clientId);
return ResponseWrapper.wrap(clientDTO);
}
Now, you want your REST method doing ONLY this and nothing else. Otherwise, you would put block-bruteforce-and-spam-logic in your REST method and you would get a mess of the code that is not extensible, hard to version, etc. If you want to change your, e.g. blacklisting policy you would have to change each and every REST method, and it's bulky. If you want to check the calls before the make it to REST methods, then take a look at Filters. Every request and response pass through a chain of filters and could be check for misuse of the server.
I don't know what is your technology stack is, but I would suggest looking into these:
JBoss AS7.
DeltaSpike (enables you powerful Interceptors that will check user rights and execution rights before the execution of the REST method).
for example:
#LoggedInUser
#GET
public Response getClientInfo(...) {
...
}
This security annotation #LoggedInUser (which, by the way, you define) will give sign to an Interceptor to check this security constraint, e.g.
#Secures (built in annotation)
#LoggedInUser
public boolean hasRight(Identity identity) {
return identity.isLoggedIn(); //or if he is in certain group of users
}
Context and Dependency Injection context (used in DeltaSpike).
JBoss Filters (a filter chain where you can create your own filter that, for example, checks if some IP is trying to send multiple calls within a very short period ~ 10 lines of code).
An example of the Filter
#Startup
#ApplicationScoped
#Filter(around= "org.jboss.seam.web.ajax4jsfFilter")
public class IPTrackerFilter extends AbstractFilter {
//IPTracker is your #ApplicationScoped bean that remembers all IP addresses accessing the application.
#Inject
private IPTracker fIPTracker;
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
if (!(req instanceof HttpServletRequest)) {
chain.doFilter(req, res);
return;
}
final String ipAddress= ((HttpServletRequest)req).getRemoteAddr();
if (fIPTracker.isBlackListed(ipAddress)) {
//implement error message here
sendErrorMessage(response);
return;
} else {
//all good, continue
chain.doFilter(req, res);
}
}
}
PS. I gave you the link for DeltaSpike, for others is really easy to find. Also, if you find DeltaSpike to obscure, try with JBoss Seam Security Framework.
My setup is as follows
A main application servlet accessible under /myApp/mainServlet/
A little "hand made" soap proxy that adds security headers (usernames, passwords) to soap calls coming from a client
A Flex client that talks to the main servlet (through a BlazeDS interface), and sends some soap calls to a third party through this soap proxy
The flex client has a session id which is set when it first talks to the main servlet and it returns a HTTP header such as "Set-Cookie: "JSESSION: something; Path=/myApp". This cookie is then sent the the server to inform of which session the client is associated to.
The problem is that the little soap proxy also returns a cookie with a session id (for each call made through it) - and the Flex client then uses these cookies when talking to the main servlet. These other session ids are unknown to it, and then of course nothing works ...
I do not want a session cookie to be returned from the soap proxy, and I have verified that the problem would be solved by doing so by telling an Apache front-end to strip all "Set-Cookie" headers coming from the soap proxy. Unfortunately (due to some setup restrictions), this is not a way I can go in production, and so I will need to fix it programmatically.
How can I make the servlet not try to set any session ids? I believe I have seen ways of telling Jetty (the app server) not to send sessions ids, but that would also affect the main servlet's ability to do so as well, and is also not portable.
The proxy servlet is a very basic Spring Controller (just implementing the interface), so basically just a bare bone servlet.
Removing the cookie can be done with res.setHeader("Set-Cookie", null);
Edit: It is good to know, that this removes all cookies, since they are all set in the same header.
I recommend that you don't do it in your servlet, a Filter is better, because it's less intrusive, something like:
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws IOException, ServletException
{
HttpServletResponse res = (HttpServletResponse) response;
try
{
chain.doFilter(request, res);
}
finally
{
res.setHeader("Set-Cookie", null);
}
}
This solution is inspired by this article at randomcoder.