Skip to content

Commit fcafc05

Browse files
committed
Merge pull request #7 from decebals/csrf
Document CSRF handler
2 parents 8c771c5 + f2d16bd commit fcafc05

File tree

1 file changed

+34
-7
lines changed

1 file changed

+34
-7
lines changed

_posts/2015-03-17-security.md

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ date: 2015-03-17 17:29:19
66
order: 130
77
---
88

9-
You can secure your application or only some parts using a filter (a RouteHandler). Remember that routes are matched
10-
in the order they are added/defined so put your security filter in front of regular routes (regular routes are
9+
You can secure your application or only some parts using a filter (a RouteHandler). Remember that routes are matched
10+
in the order they are added/defined so put your security filter in front of regular routes (regular routes are
1111
endpoint routes for a request).
1212

1313
I will show you a simple implementation for a security filter.
@@ -26,12 +26,12 @@ GET("/contact.*", (routeContext) -> {
2626
// show contacts page
2727
GET("/contacts", (routeContext) -> routeContext.render("contacts"));
2828

29-
// show contact page for the contact with id specified as path parameter
29+
// show contact page for the contact with id specified as path parameter
3030
GET("/contact/{id}", (routeContext) -> {
3131
int id = routeContext.getParameter("id").toInt(0);
3232
Contact contact = (id > 0) ? contactService.getContact(id) : new Contact();
33-
routeContext.setLocal("contact", contact);
34-
33+
routeContext.setLocal("contact", contact);
34+
3535
routeContext.render("contact")
3636
});
3737

@@ -73,7 +73,7 @@ The content for login (freemarker engine) can be:
7373
<#if flash.hasError()>
7474
${flash.getError()}
7575
</#if>
76-
76+
7777
<form method="post" action="/login">
7878
<input placeholder="Username" name="username">
7979
<input placeholder="Password" name="password" type="password">
@@ -86,4 +86,31 @@ The content for login (freemarker engine) can be:
8686
In above code I want to protect all pages (contacts, contact) for the Contact domain entity.
8787
The authentication tests to see if the 'username' attribute is present in the session object. If 'username' is present
8888
than call the regular route with `routeContext.next()` else redirect to the login page.
89-
I added `originalDestination` attribute because after authentication process I want to continue with the original destination (original url).
89+
I added `originalDestination` attribute because after authentication process I want to continue with the original destination (original url).
90+
91+
### Cross-Site Request Forgery (CSRF) Protection
92+
93+
Pippo includes a simple CSRF handler which will automatically generate a CSRF token on GET requests, if there is no token in the current session, and verify that POST requests include the session's CSRF token.
94+
95+
Using this handler is straight-forward.
96+
97+
**1.** Add an `ALL` filter for the protected path expression with the `CSRFHandler`.
98+
99+
```java
100+
// add a CSRF token generator and validator
101+
ALL("/books.*", new CSRFHandler());
102+
```
103+
104+
**2.** Add a `${csrfToken}` hidden input value on all forms that are POSTed to this protected path expression
105+
106+
```html
107+
<html>
108+
<body>
109+
<form method="post" action="/books/5/rename">
110+
<input type="hidden" value="${csrfToken}" name="csrfToken" >
111+
<input placeholder="Enter a new book title" name="bookTitle">
112+
<input type="submit" value="Rename">
113+
</form>
114+
</body>
115+
</html>
116+
```

0 commit comments

Comments
 (0)