Real world
web security


public class SecurityFilter implements ContainerRequestFilter {

  @Override
  public void filter(ContainerRequestContext requestContext)
        throws IOException {

        // TODO implement security

  }

}
      

Real World!

Did you really name your son drop table?

Shame on you!

Shame on you

A URI

https://adorsys.de/esd.html

A Form


<form action="https://adorsys.de/shop/carts" method="GET">
  Shopping cart of: <input type="text" name="customerId">
  <input type="submit">
</form>
      
https://adorsys.de/shop/carts?customerId=4711

A Request

  • URI
  • Body
  • Header
  • (Cookies)
https://www.adorsys.de/shop.jsp
;jsessionid=557206C363F1267A24AB769CA0DE4529.node01

Session-Config (web.xml)


<?xml version="1.0" encoding="UTF-8"?>
<web-app
  xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
  http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  metadata-complete="true" version="3.0">

  <session-config>
    <tracking-mode>URL</tracking-mode>
    <tracking-mode>COOKIE</tracking-mode>
    <tracking-mode>SSL</tracking-mode>
  </session-config>

</web-app>
      

Session-Config (web.xml)


<session-config>
  <session-timeout>30</session-timeout>
  <cookie-config>
    <http-only>true</http-only>
    <secure>true</secure>
  </cookie-config>
  <tracking-mode>COOKIE</tracking-mode>
</session-config>
      

@WebServlet("/login")
public class LoginServlet extends HttpServlet {

  @Override
  protected void doGet(HttpServletRequest req,
        HttpServletResponse res)
        throws ServletException, IOException {

      if (login(req.getParameter("user"), req.getParameter("pw"))) {
        response.sendRedirect("/home");
      } else {
        response.sendRedirect("/login-failed");
      }

    }

}
      

Renew the session


// Java EE 7
request.changeSessionId();

// Jave EE 6
request.getSession(false).invalidate();
request.getSession(true);
      
Session fixation
https://www.adorsys.de/shop
?access_token=0eb3f7c6-4396-4f11-beae-d0cd5010237e
https://www.adorsys.de/shop/customers/4dcfbb3c6a4f1d4c4a000012
https://adorsys.de/money-transfer?to=4dcfbb3c6a4f1d4c4a000012&amount=5000

XSRF / CSRF


<a href="https://adorsys.de/money-transfer?to=4dcfbb3c6a4f1d4c4a000012&amount=5000"
        >Show me Kittens!</a>

<img src="https://adorsys.de/money-transfer?to=4dcfbb3c6a4f1d4c4a000012&amount=5000"
        width="0" height="0">
      
CSRF

CSRF via POST


<form action="https://adorsys.de/money-transfer" method="POST" id="form">
  <input type="hidden" name="to" value="4dcfbb3c6a4f1d4c4a000012">
  <input type="hidden" name="amount" value="5000">
  <input type="submit" value="Show me Kittens!">
</form>

<img src="kittens.png"
  onmouseover="document.getElementById('form').submit(); return false;">
      

CSRF Protection (Server Side)


<input type="hidden"
  name="xsrf-token"
  value="8dcfbb3c6a4f1d4c4a372997">
      

CSRF Protection (Angular)


Server: Set-Cookie: XSRF-TOKEN=4dcfbb3c6a4f1d4c4a000012

$http: X-XSRF-TOKEN: 4dcfbb3c6a4f1d4c4a000012
      

CSRF on a JSON API?


<form enctype="text/plain">

-> @Consumes("application/json")

XHR requests

-> Access-Control-Allow-Origin: https://api.com
      

SOP

CORS

CORS Header


        Access-Control-Allow-Origin: *
      

CSP Header


Content-Security-Policy: default-src 'self';
  script-src 'self' 'https://apis.google.com';
  connect-src 'self' 'https://my.api.com';
  img-src 'self' 'https://static.cdn.com';
      
Content Security Policy Reference

Cookieless Login


@Path("/login")
public class LoginResource {

  @POST
  public Response login(@Context HttpServletRequest req) {
    if (basicAuth(req)) {
      return Response.ok()
              .header("X-AUTH-TOKEN", UUID.randomUUID()).build();
    } else {
      return Response.status(403).build();
    }
  }

}
      

Token Storage


$http.post('/login', credentials).then(function(response) {
  $httpProvider.defaults.headers.common['X-AUTH-TOKEN']
    = response.data.token;

  // for page reloads...
  $cookies.put('X-AUTH-TOKEN', response.data.token);
  $window.localStorage.setItem('X-AUTH-TOKEN', response.data.token);
  $window.sessionStorage.setItem('X-AUTH-TOKEN', response.data.token);
});
      

<%@ page contentType="text/html; charset=utf-8" %>
<!doctype html>
<html>
<head>
  <title>A JSP</title>
</head>
<body>
  <h1>Hello ${param.name}</h1>
</body>
</html>
      
https://adorsys.de/shop
?name=<script>alert('bubu');</script>

XSS Prevention (JSP)


<c:out value="${param.name}"/>

${fn:escapeXml(param.name)}
      
Java Web Application Enhancements Library

<!doctype html>
<html ng-app="myApp">
<head>
  <title>A JSP</title>
</head>
<body>
  <h1>Hello {{ location.search().name }}</h1>
</body>
</html>
      

XSS Prevention (Angular)


// $sce enabled per default since 1.2, but:
$translateProvider.useSanitizeValueStrategy('sanitize');
      

app.post('/login', function(req, res) {
  db.users.find({
    username: req.body.username,
    password: req.body.password
  }, function (err, users) {
    // login successful!
  });
});
      

Mongo
SQL Injection


{
  "username": {"$gt": ""},
  "password": {"$gt": ""}
}

// also possible with Java Driver
BasicDBObject query = (BasicDBObject) JSON.parse(json);
      
Hacking NodeJS and MongoDB

btw...

30.000 MongoDB Instances accessible over the Internet without any authorization

src/main/resources/jboss.properties


db.host=192.168.3.3
db.port=28017
api.secret=xdJF3f9fs3OJfs
# for PROD
# api.secret=2ddoU3fP12cv
      

OWASP Dependency Check


<build>
  <plugins>
    <plugin>
      <groupId>org.owasp</groupId>
      <artifactId>dependency-check-maven</artifactId>
      <version>1.3.5.1</version>
      <executions>
        <execution>
          <goals>
            <goal>check</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>
      

public Response importCsv(InputStream stream) throws Exception {
  BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
  List<ErrorDetail> errors = new ArrayList<>();
  String line;
  while ((line = reader.readLine())) != null) {
    if (!importCsvLine(line)) {
      errors.add(new ErrorDetail(line));
    }
  }
  reader.close();
  return errors.isEmpty()
    ? Response.ok().build()
    : Response.status(400).entity(errors).build();
}
      
OWASP Top Ten 2013

JSR 375

Soteria

Thanks