I am developing a website using Spring Boot 1.5.7 as back-end and Angular 2 as front-end.
I am a newbie on both technologies, and it's the very first time I try to develop a website. So I am a bit confused on many things.
I have implemented user authentication through JWT.
When the user logins through credentials, the backend verifies them and then creates a JWT and returns it to the frontend: the token is added to the header this way:
Authorization - Bearer <jwt token>
In the frontend I check out if that key is in the post response. If it is there, I add it along with the username to the localStorage.
private authUrl = 'http://localhost:8080/login';
private headers = new Headers({
'Content-Type': 'application/json',
'Accept': 'application/json'
});
constructor(private http: Http) { }
login(username: string, password: string): Observable<void> {
let loginRequest = JSON.stringify({ username: username, password: password });
return this.http.post(this.authUrl, loginRequest, { headers: this.headers })
.map((response: Response) => {
let token = response.headers.get('Authorization');
// If token is not null, empty or undefined.
if (token) {
localStorage.setItem('jwt', JSON.stringify({ username: username, token: token }));
}
});
}
When the user is logged in, everytime he accessed a protected resource, a token will be retrieved from the localStorage and sent back to the backend for validation.
The whole thing works. JWT are immune to CSRF, so I can disable that in the back-end,
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
...
but I have read (for instance, here) that there are vulnerabilities when using localStorage.
In particular the localStorage is accessible through JavaScript on the same domain, exposing to XSS attacks.
To resolve it seems I could use a JWT Cookie. As written in the link before, I could set the HttpOnly cookie flag to avoid cookies to be accessed through JavaScript.
But, with cookies I am now vulnerable to CRSF attacks.
Now, here, I have read Angular 2+ provides built-in, enabled by default, anti XSS.
So the question is. I should use localStorage and just use the embedded Angular 2 anti XSS feature, or is that not enough and then I should store JWTs on cookies to get protection against XSS attacks and then implement on top of it some kind of CRSF protection backend side using Spring Boot configuration?
Thank you
EDIT: the website is a sort of shopping cart. The user can view almost all
pages, but to pay he needs to log in.
Aniruddha Das approach is fine but client application will lost the token if user will refresh the browser because DOM will be reloaded with browser refresh and all memory data including token will be lost.
Now come back to your approach-
Local storage - CSRF attack is not possible using this approach and application will be stateless but it is prone to XSS attack. By default Angular do the output encoding to prevent the XSS attack but risk is still there with server side Angular template. To mitigate the XSS attack, you can reduce the token expiry time and encrypt it, if there is some sensitive information.
Cookie approach - HTTP cookie will mitigate the XSS attack but you have to implement the CSRF protection. You have to use the API gateway pattern to make the application stateless.
Both approach have prons/cons and you have to select depending on your application. If your application is related to financial domain then I would suggest cookie based approach.
In angular you can hold your token in service and use it when ever it required. Like pojo in java in angular you can create a angular service with getter and setter to hold the token. Provide that service to the module and it will available in all component and directives.
The token will be in memory while the application is open in the browser and will be be stored in the browser.
I would say use a observable/Subject type variable so that it will wait until the token is extracted from server and use that to do stuffs.
Related
I am trying to secure some of my spring cloud gateway routes:
Users must be authenticated using OAUTH2 to be able to use those routes (if not -> respond with http 401)
The JWT access token must include a specific value in the "scp" claim ("2fa" in my case) (if not, respond with http 403)
The JSON payload contains one property "user" that must have the same value as the "sub" claim in the JWT access token. (if not, respond with http 403)
Reading the documentation I found out how I can set up 1. and 2.
Unfortunately, there seems to be very little information on how to achieve 3.
Where I could I find a working example?
Here's my spring security setup from application.yaml file:
...
spring:
profiles: production
security:
oauth2:
resourceserver:
jwt:
issuer-uri: ${AUTH_URL}/oidc
jwk-set-uri: ${AUTH_URL}/oidc/jwks.json
...
Configuation of my SecurityWebFilterChain:
...
#Bean
#Order(Ordered.HIGHEST_PRECEDENCE - 3)
public SecurityWebFilterChain secondFactorScopeApiHttpSecurity(ServerHttpSecurity http) {
final ServerWebExchangeMatcher baseScopeEndpointsMatcher = new OrServerWebExchangeMatcher(
new PathPatternParserServerWebExchangeMatcher("/api/fhir"),
new PathPatternParserServerWebExchangeMatcher("/api/fhir/List**"),
new PathPatternParserServerWebExchangeMatcher("/api/fhir/Observation**")
);
http.securityMatcher(baseScopeEndpointsMatcher)
.authorizeExchange(exchanges -> exchanges.anyExchange().hasAuthority("SCOPE_2fa"))
.oauth2ResourceServer(ServerHttpSecurity.OAuth2ResourceServerSpec::jwt);
return http.build();
}
...
I want the user to see a HTTP 403 in case the payloads "user" property does not match the sub claim from the JWT.
What you want to achieve is an easy task on resource-servers and, in my opinion, resources access-control is the responsability of resource-server, not gateway, specially if access decision involves the resource itself.
I would just let the gateway be transparent to OAuth2: leave requests authorization header as well as responses status code unchanged.
I have samples in that series of tutorials which incrementally builds to advanced role based access control. It should take you less than an hour to follow the first 3:
1st demoes resource-server security conf with spring-boot-starter-oauth2-resource-server (what you've implemented on the gateway so far)
2nd shows how to replace JwtAuthenticationToken with an implementation of your choice exposing strongly typed private-claims. It also greatly reduce Java conf with one of the thin wrappers I created around spring-boot one.
3rd demoes security SpEL customization to write stuff like
#GetMapping("/on-behalf-of/{username}")
#PreAuthorize("is(#username) or isNice() or onBehalfOf(#username).can('greet')")
public String getGreetingFor(#PathVariable("username") String username) {
...
}
Of course, in your case, you would use a signature like myControllerMethod(#RequestBody MyDto dto, Authentication auth) and an expression like #dto.sub eq #auth.name, but you get the idea.
What i found while using spring oauth framework is resource server making check_token?token=T_O_K_E_N request to authorisation server, and authorisation server is just returning CheckTokenEndPoint map with authorities something like below.
{
"exp": 1511471427,
"user_name": "idvelu",
"authorities": [
"FUNCTION_GET_USERS",
"FUNCTION_AUTHORITY_1",
"FUNCTION_AUTHORITY_2",
"FUNCTION_AUTHORITY_3",
"FUNCTION_AUTHORITY_4",
"FUNCTION_AUTHORITY_5",
"FUNCTION_AUTHORITY_6",
"FUNCTION_AUTHORITY_7",
],
"client_id": "c1",
"scope": [
"read",
"write"
]
}
Just visualise this with oauth service and resource service is running in two different machines/jvm.
I think now resource server has to authorise the request against configured valid authorities in ResourceServerConfiguration::configure(HttpSecurity) with the authorities from the authorisation server.
#Override
public void configure(HttpSecurity http) throws Exception {
http.anonymous().disable().requestMatchers().antMatchers("/**").and().authorizeRequests()
.antMatchers(HttpMethod.GET, "/myproject/users").hasAnyAuthority("FUNCTION_GET_USERS")
.antMatchers(HttpMethod.POST, "/myproject/users").hasAnyAuthority("FUNCTION_POST_NEW_USER")
.anyRequest().denyAll()
.and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
In this case authorisation server may return all the hundreds of user authorities to resource server. Instead why not authorisation server itself can take the few of the permission required for authorisation as query params check_token?token=T_O_K_E_N&authorities=FUNCTION_GET_USERS,FUNCTION_AUTHORITY_2,.. from the resource server and validate it against the user's functions through DB?
And finally my problem is; i have different services like java, node.js, NGINX... All these have to verify its authentication and authorization against one spring Authorisation server. Because of the above stated problem all my service has to implement the authorisation (resource server) part. Means comparing all the authorities of user against the API acess authorities. Java side this comparison is fine with spring resource server implementation. But all other non-java (resource) services needs authorisation/resourceServer implementation. Instead if my spring authorisation server accepts the authorities and validates then my problem is solved as single point of authorisation/comparison implementations. I just need to pass it as part of check_token.
How to implement this new check_token endpoint along with accepting the authorities?
The authorization server is responsible for authenticating the user/client (depending on the oauth type you use). When this is done, a token is given.
When a user/client presents themselves to the resource server, wanting to consume a service, they must provide the token. Now the resource server has a token and needs to validate that this token was generated by the authorization server. There are two options:
The token itself does not contain any information. The resource server calls the authorization server and asks if the token is valid. The authorization server will respond that the token is valid and gives some additional information (user/client, roles/scopes, etc).
The token does contain the necessary information (JWT tokes for example). This enables the resource server to extract the needed info without contacting the authorization server. In this case, the authorization server has signed the token and the resource server can validate the signature to be sure that it was the autorization server that has issued the token.
At the moment, you are using the first scenario. Every resource server you write, must verify tokens and extract additional info. How the verification is done depends on the authorization server.
Part2:
Your question is not clear to me. I presume you are using the OAuth2 authorization code scheme with non JWT tokens?
In that case, you have an authorization server that is only responsible for authentication, a resource server that is exposing some services and a client that consumes the resource server.
If i'm not mistaking, you have different resource servers (api's)?
You did not share your authorization server configurations, but normaly you use #EnableAuthorizationServer. This will create an endpoint /oauth/check_token. By default this endpoint is not accassible. You need to do something like this:
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception
{
oauthServer.checkTokenAccess("permitAll()"); // authenticated is better
}
You can use this endpoint to validate tokens.
All this is described in the oauth2 developer guide.
Part3:
On the authorization server, you can create an endpoint like this :
#RequestMapping("/user")
public Principal user(Principal principal) {
if(principal instanceof OAuth2Authentication) {
return (OAuth2Authentication) principal;
} else {
return principal;
}
}
You can modify it to your needs.
As restful service stateless, it don't maintain any interaction of user, so i want to know if multiple user accessing same restful service, then how restful service identify which user interact with which method ? and is it possible to make restful service as stateful ?
Which user:
By using a shared secret (a line of chars), created on the server, and returned with every next request.
It's "saved" in a cookie and returned by the client, using either a cookie or a HTTP(S) header.
Which method:
This depends on the framework you use. But eventually it comes down to mapping URI's to your methods.
and is it possible to make restful service as stateful ?
You can make stateful apps, then they are not restful. A restful app is stateless. That's the definition, so you can make stateful apps, but you can never create a stateful rest-app, as rest is stateless.
tl;dr
The client must store its own session state and pass it around to the server in each request.
The stateless constraint
The stateless constraint of the REST architectural style is define as follows:
5.1.3 Stateless
[...] each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server. Session state is therefore kept entirely on the client. [...]
Authentication
If the client requests protected resources that require authentication, every request must contain all necessary data to be properly authenticated/authorized. See this quote from the RFC 7235:
HTTP authentication is presumed to be stateless: all of the information necessary to authenticate a request MUST be provided in the request, rather than be dependent on the server remembering prior requests.
And authentication data should belong to the standard HTTP Authorization header. From the RFC 7235:
4.2. Authorization
The Authorization header field allows a user agent to authenticate itself with an origin server -- usually, but not necessarily, after receiving a 401 (Unauthorized) response. Its value consists of credentials containing the authentication information of the user agent for the realm of the resource being requested. [...]
The name of this HTTP header is unfortunate because it carries authentication instead of authorization data.
For authentication, you could use the Basic HTTP Authentication scheme, which transmits credentials as username and password pairs, encoded using Base64:
Authorization: Basic <credentials>
If you don't want to send the username and password in each request, the username and password could be exchanged for a token (such as JWT) that is sent in each request. A JWT token can contain the username, an expiration date and any other metadata that may be relevant for your application:
Authorization: Bearer <token>
See this answer for more details.
According to my point of view Restful web service make as a stateless.it's architectural style which have set of constraints and properties so stateless is its properties we cannot change its properties so its doesn't mean that restful service is stateful .
we can mapped URI's to your method then restful know which user is calling which method.
I'm familiar with implementing BasicAuth security in Dropwizard, but only for RESTful endpoints/resources.
I am now experimenting with Dropwizard Views to see if I can use it to be both a web and REST server all in one. The web app will have "public" pages (that are really just static HTML files; "About Us", "Contact Us", etc.) as well as "private" (dynamic) pages, which really form the app. To get to these pages the user must be authenticated (logged in).
So this means I have the need for two distinct DW authentication mechanisms:
A typical DW security mechanism for authenticating REST API clients, which I'm familiar with; and
A way to implement a log in system for authenticating end users for the web app pages/resources
Ideally, I'd like Apache Shiro to handle all auth for my system (REST and web alike), and I see the Dropwizard-Shiro lib, but that seems to only authenticate REST endpoints.
My web login system need to work like so:
A user tries to go to an "authenticated" (private) URL.
A servlet filter (that I create myself and register with the environment) intercepts the request and can tell (perhaps a cookie/session var?) whether the user is authenticated or not.
If the user is authenticated, they are allowed to proceed to their intended URL ("target URL"). Otherwise they are redirected to a login page. When they login a DW resource/controller hands their credentials off to Shiro, who then decides whether the credentials are valid or not.
If the credentials are valid, they get a cookie/session var (?) and are redirected to their target URL. Otherwise they are redirected back to the login page which will now display a failure message.
My main concerns are:
* What should I implement for the cookie/session var that the servlet will check for?; and
* How do I integrate my auth controller (that is, the resource that handles redirection between the login page and the target URL) with Shiro? Is it possible to do this via that Dropwizard-Shiro lib?
My best attempt thus far:
Custom Servlet Filter (registered with environment):
public class AuthFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext requestContext,
ContainerResponseContext responseContext) {
Cookie[] cookies = requestContext.getCookies();
boolean authenticated = false;
for(Cookie cookie : cookies) {
// 1. This is my first concern. What is better/more secure
// than what I'm doing here?
if("my_app_auth_cookie".equals(cookie.getName())) {
authenticated = true;
}
}
if(authenticated == false) {
responseContext.sendDirect("/auth/login");
}
}
}
If they are not authenticated they redirect to /auth/login which hits a AuthController (again, registered with the environment as a resource):
#Path("/auth")
#Produces(MediaType.TEXT_HTML)
public class AuthController {
#GET
#Path("/login")
public LoginPageView login() {
// Render some "login.ftl" template as HTML.
}
#POST
#Path("/authenticate")
public ??? authenticate(??? username, ??? password) {
// 2. Somehow send 'username' and 'password' to Shiro...
MyAppUser user = myAppRealm.authenticate(username, password);
// Now what do I do with 'user'?
}
}
When the user submits the form on the login page (which might be a POST to /auth/authenticate) we somehow hand their inputted credentials off to Shiro (again I'd like to use that Dropwizard-Shiro lib since I will likely also be using it for my REST endpoints).
Apache Shiro has its own type of filters which are configured in shiro.ini.
Example:
[urls]
/api/** = noSessionCreation, authcBasic
/views/login = authc
/views/authenticated = authc, user
Configure the authc filter to redirect to a login form page that you implement. Use the filter's form parameters and POST to /views/login.
If you enable the session manager in Jetty, Shiro should create servlet sessions when they log in from the login form page.
Please note that I haven't actually tested this configuration.
I'm trying to make a webapp that will run on a single HTML page that will allow users to interact with the server through JavaScript and ajax. I'd like to make my requests safe against csrf attacks by including a csrf token in each request.
Because my webapp will only be operating on a single page, I can't use the ${_csrf.token} (or something like that) syntax in the view because the view is going to be a json object. Instead I'd like to have a url like "/security/csrf" that returns a token associated with the user's session. (Yes, this won't be a restful service exactly.)
Is there some way for me to generate a csrf token that Spring Security will be able to access when verifying a log-in? And additionally, is there a flaw in using csrf tokens in this way?
Token per request will kill caching. Token per session is just as safe.
In your first html response, include the csrf token in a meta tag, like the docs say: http://docs.spring.io/spring-security/site/docs/current/reference/html/csrf.html#csrf-include-csrf-token-ajax
You can use the same token across requests (in the same session)