CSRF/XSRF ochrana při hlasování.
authorFrantišek Kučera <franta-hg@frantovo.cz>
Sat, 15 Jan 2011 18:14:15 +0100
changeset 174ca3c7dd220fe
parent 173 2b458ac09044
child 175 a121def64733
CSRF/XSRF ochrana při hlasování.
java/nekurak.net-lib/src/cz/frantovo/nekurak/preklady_cs.properties
java/nekurak.net-lib/src/cz/frantovo/nekurak/xml/HlasXML.java
java/nekurak.net-web/src/java/cz/frantovo/nekurak/posluchac/OchranaProtiCSRF.java
java/nekurak.net-web/src/java/cz/frantovo/nekurak/rest/HlasovaniREST.java
java/nekurak.net-web/web/WEB-INF/tags/nekurak/stranka.tag
java/nekurak.net-web/web/WEB-INF/web.xml
java/nekurak.net-web/web/js/hlasovani.js
java/nekurak.net-web/web/styl.css
     1.1 --- a/java/nekurak.net-lib/src/cz/frantovo/nekurak/preklady_cs.properties	Sat Jan 15 14:27:02 2011 +0100
     1.2 +++ b/java/nekurak.net-lib/src/cz/frantovo/nekurak/preklady_cs.properties	Sat Jan 15 18:14:15 2011 +0100
     1.3 @@ -43,7 +43,7 @@
     1.4  prihlaseni.tlacitko=P\u0159ihl\u00e1sit se
     1.5  
     1.6  pridatPodnik.nadpis=P\u0159id\u00e1n\u00ed nov\u00e9ho podniku
     1.7 -pridatPodnik.bylPridan=Podnik byl \u00fasp\u011b\u0161n\u011b p\u0159id\u00e1n.
     1.8 +pridatPodnik.bylPridan=Podnik byl \u00fasp\u011b\u0161n\u011b p\u0159id\u00e1n. Zobrazovat se bude po schv\u00e1len\u00ed spr\u00e1vcem.
     1.9  pridatPodnik.nebylPridan=P\u0159i p\u0159id\u00e1v\u00e1n\u00ed podniku do\u0161lo k chyb\u011b. Zkontrolujte pros\u00edm zadan\u00e9 \u00fadaje.
    1.10  pridatPodnik.tlacitko=P\u0159idat podnik
    1.11  
    1.12 @@ -146,4 +146,4 @@
    1.13  
    1.14  chat.nadpis=Chat
    1.15  chat.anonym=Kolemjdouc\u00ed
    1.16 -chat.tlacitkoOdeslat=Odeslat
    1.17 +chat.tlacitkoOdeslat=Odeslat
    1.18 \ No newline at end of file
     2.1 --- a/java/nekurak.net-lib/src/cz/frantovo/nekurak/xml/HlasXML.java	Sat Jan 15 14:27:02 2011 +0100
     2.2 +++ b/java/nekurak.net-lib/src/cz/frantovo/nekurak/xml/HlasXML.java	Sat Jan 15 18:14:15 2011 +0100
     2.3 @@ -12,6 +12,7 @@
     2.4  
     2.5  	private int podnik;
     2.6  	private boolean kourit;
     2.7 +	private String csrfToken;
     2.8  
     2.9  	@XmlElement
    2.10  	public int getPodnik() {
    2.11 @@ -30,4 +31,13 @@
    2.12  	public void setKourit(boolean hlas) {
    2.13  		this.kourit = hlas;
    2.14  	}
    2.15 +
    2.16 +	@XmlElement
    2.17 +	public String getCsrfToken() {
    2.18 +		return csrfToken;
    2.19 +	}
    2.20 +
    2.21 +	public void setCsrfToken(String csrfToken) {
    2.22 +		this.csrfToken = csrfToken;
    2.23 +	}
    2.24  }
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/java/nekurak.net-web/src/java/cz/frantovo/nekurak/posluchac/OchranaProtiCSRF.java	Sat Jan 15 18:14:15 2011 +0100
     3.3 @@ -0,0 +1,23 @@
     3.4 +package cz.frantovo.nekurak.posluchac;
     3.5 +
     3.6 +import javax.servlet.http.HttpSessionEvent;
     3.7 +import javax.servlet.http.HttpSessionListener;
     3.8 +
     3.9 +/**
    3.10 + *
    3.11 + * @author fiki
    3.12 + */
    3.13 +public class OchranaProtiCSRF implements HttpSessionListener {
    3.14 +
    3.15 +	public static final String NAZEV_ATRIBUTU = "CSRF_TOKEN";
    3.16 +
    3.17 +	@Override
    3.18 +	public void sessionCreated(HttpSessionEvent se) {
    3.19 +		String csrfToken = String.valueOf(Math.random());
    3.20 +		se.getSession().setAttribute(NAZEV_ATRIBUTU, csrfToken);
    3.21 +	}
    3.22 +
    3.23 +	@Override
    3.24 +	public void sessionDestroyed(HttpSessionEvent se) {
    3.25 +	}
    3.26 +}
     4.1 --- a/java/nekurak.net-web/src/java/cz/frantovo/nekurak/rest/HlasovaniREST.java	Sat Jan 15 14:27:02 2011 +0100
     4.2 +++ b/java/nekurak.net-web/src/java/cz/frantovo/nekurak/rest/HlasovaniREST.java	Sat Jan 15 18:14:15 2011 +0100
     4.3 @@ -1,5 +1,6 @@
     4.4  package cz.frantovo.nekurak.rest;
     4.5  
     4.6 +import cz.frantovo.nekurak.posluchac.OchranaProtiCSRF;
     4.7  import cz.frantovo.nekurak.util.HttpPozadavek;
     4.8  import cz.frantovo.nekurak.web.HledacSluzby;
     4.9  import cz.frantovo.nekurak.xml.HlasXML;
    4.10 @@ -23,7 +24,16 @@
    4.11  	@Consumes(MIME_XML)
    4.12  	@Produces(MIME_TEXT)
    4.13  	public String hlasuj(HlasXML xml) {
    4.14 +		zkontrolujCSRF(pozadavek, xml);
    4.15  		hledac.getPodnikEJB().hlasuj(xml.getPodnik(), xml.isKourit(), HttpPozadavek.getIPadresa(pozadavek));
    4.16  		return "ok";
    4.17  	}
    4.18 +
    4.19 +	private static void zkontrolujCSRF(HttpServletRequest pozadavek, HlasXML xml) throws RuntimeException {
    4.20 +		String csrfTokenOcekavany = (String) pozadavek.getSession().getAttribute(OchranaProtiCSRF.NAZEV_ATRIBUTU);
    4.21 +		String csrfTokenObdrzeny = xml.getCsrfToken();
    4.22 +		if (csrfTokenOcekavany == null || !csrfTokenOcekavany.equals(csrfTokenObdrzeny)) {
    4.23 +			throw new RuntimeException("CSRF token zaslaný klientem neodpovídá očekávanému.");
    4.24 +		}
    4.25 +	}
    4.26  }
     5.1 --- a/java/nekurak.net-web/web/WEB-INF/tags/nekurak/stranka.tag	Sat Jan 15 14:27:02 2011 +0100
     5.2 +++ b/java/nekurak.net-web/web/WEB-INF/tags/nekurak/stranka.tag	Sat Jan 15 18:14:15 2011 +0100
     5.3 @@ -43,6 +43,7 @@
     5.4  			<meta name="robots" content="index, follow" />
     5.5  		</head>
     5.6  		<body>
     5.7 +			<p id="csrfToken"><c:out value="${sessionScope['CSRF_TOKEN']}"/></p>
     5.8  			<div class="body">
     5.9  
    5.10  				<div id="horniPruh">
     6.1 --- a/java/nekurak.net-web/web/WEB-INF/web.xml	Sat Jan 15 14:27:02 2011 +0100
     6.2 +++ b/java/nekurak.net-web/web/WEB-INF/web.xml	Sat Jan 15 18:14:15 2011 +0100
     6.3 @@ -8,16 +8,19 @@
     6.4  	</welcome-file-list>
     6.5      <!-- <chybovéStránky> -->
     6.6  	<error-page>
     6.7 -	<!-- Stránka nenalezena -->
     6.8 +        <!-- Stránka nenalezena -->
     6.9  		<error-code>404</error-code>
    6.10  		<location>/WEB-INF/chyby/404.jsp</location>
    6.11  	</error-page>
    6.12  	<error-page>
    6.13 -	<!-- Interní chyba serveru -->
    6.14 +        <!-- Interní chyba serveru -->
    6.15  		<error-code>500</error-code>
    6.16  		<location>/WEB-INF/chyby/500.jsp</location>
    6.17  	</error-page>
    6.18      <!-- </chybovéStránky> -->
    6.19 +	<listener>
    6.20 +		<listener-class>cz.frantovo.nekurak.posluchac.OchranaProtiCSRF</listener-class>
    6.21 +	</listener>
    6.22      <!-- <definiceServletů> -->
    6.23  	<servlet>
    6.24  		<servlet-name>atom</servlet-name>
    6.25 @@ -70,7 +73,7 @@
    6.26  		<url-pattern>/kaptcha.jpg</url-pattern>
    6.27  	</servlet-mapping>
    6.28  	<servlet-mapping>
    6.29 -	<!-- Veřejné REST API -->
    6.30 +        <!-- Veřejné REST API -->
    6.31  		<servlet-name>REST</servlet-name>
    6.32  		<url-pattern>/zdroje/*</url-pattern>
    6.33  	</servlet-mapping>
    6.34 @@ -80,7 +83,7 @@
    6.35  	</servlet-mapping>
    6.36      <!-- </mapováníServletů> -->
    6.37  	<context-param>
    6.38 -	<!-- Pro případ, že chybí hlavička „Accept-language“ v HTTP požadavku -->
    6.39 +        <!-- Pro případ, že chybí hlavička „Accept-language“ v HTTP požadavku -->
    6.40  		<param-name>javax.servlet.jsp.jstl.fmt.fallbackLocale</param-name>
    6.41  		<param-value>cs</param-value>
    6.42  	</context-param>
     7.1 --- a/java/nekurak.net-web/web/js/hlasovani.js	Sat Jan 15 14:27:02 2011 +0100
     7.2 +++ b/java/nekurak.net-web/web/js/hlasovani.js	Sat Jan 15 18:14:15 2011 +0100
     7.3 @@ -1,7 +1,8 @@
     7.4  var hlasovani = {};
     7.5  
     7.6  hlasovani.hlasuj = function (podnik, hlas) {
     7.7 -	var pozadavek = "<hlas><kourit>" + hlas + "</kourit><podnik>" + podnik + "</podnik></hlas>";
     7.8 +	var csrfToken = document.getElementById("csrfToken").innerHTML;
     7.9 +	var pozadavek = "<hlas><kourit>" + hlas + "</kourit><podnik>" + podnik + "</podnik><csrfToken>" + csrfToken + "</csrfToken></hlas>";
    7.10  
    7.11  	$.ajax({
    7.12  		type: "POST",
    7.13 @@ -10,14 +11,12 @@
    7.14  		contentType: "text/xml",
    7.15  		dataType: "text",
    7.16  		success: function(odpoved) {
    7.17 -			if (odpoved == "ok") {
    7.18 -				/** TODO: předělat informaci – nepoužívat alert ale text v SVG */
    7.19 -				/** TODO: Lokalizace */
    7.20 -				alert("Váš hlas byl přijat.");
    7.21 -			} else {
    7.22 -				/** TODO: předělat ošetřování chyb */
    7.23 -				alert("Při hlasování došlo k chybě.");
    7.24 -			}
    7.25 +			/** TODO: Lokalizace */
    7.26 +			alert("Váš hlas byl přijat.");
    7.27 +		},
    7.28 +		error: function(odpoved) {
    7.29 +			/** TODO: Lokalizace */
    7.30 +			alert("Při hlasování došlo k chybě. Zkuste obnovit stránku (F5) a opakujte hlasování.");
    7.31  		}
    7.32  	});
    7.33  };
     8.1 --- a/java/nekurak.net-web/web/styl.css	Sat Jan 15 14:27:02 2011 +0100
     8.2 +++ b/java/nekurak.net-web/web/styl.css	Sat Jan 15 18:14:15 2011 +0100
     8.3 @@ -15,6 +15,10 @@
     8.4      margin: 0 auto;
     8.5  }
     8.6  
     8.7 +#csrfToken {
     8.8 +	display: none;
     8.9 +}
    8.10 +
    8.11  #horniPruh {
    8.12      width: 1000px;
    8.13      border: 1px solid silver;