[jetrix-cvs] SF.net SVN: jetrix:[847] jetrix/trunk/src
Brought to you by:
smanux
From: <sm...@us...> - 2010-05-03 18:13:58
|
Revision: 847 http://jetrix.svn.sourceforge.net/jetrix/?rev=847&view=rev Author: smanux Date: 2010-05-03 18:13:52 +0000 (Mon, 03 May 2010) Log Message: ----------- Added two protection mechanisms against potential attacks: - slow clients are rejected to avoid Slowloris-like denial of service - messages over 8K are rejected to avoid filling the server memory Modified Paths: -------------- jetrix/trunk/src/java/net/jetrix/protocols/AbstractProtocol.java jetrix/trunk/src/test/net/jetrix/protocols/TetrinetProtocolTest.java Modified: jetrix/trunk/src/java/net/jetrix/protocols/AbstractProtocol.java =================================================================== --- jetrix/trunk/src/java/net/jetrix/protocols/AbstractProtocol.java 2010-05-03 15:29:44 UTC (rev 846) +++ jetrix/trunk/src/java/net/jetrix/protocols/AbstractProtocol.java 2010-05-03 18:13:52 UTC (rev 847) @@ -35,19 +35,36 @@ */ public abstract class AbstractProtocol implements Protocol { - public String readLine(InputStream in) throws IOException + /** Maximum size allowed for a message frame. */ + private static final int MAX_SIZE = 8192; + + /** Maximum delay allowed for parsing a message frame (in milliseconds). */ + private static final int MAX_DELAY = 10000; + + /** + * Reads the next message frame from the specified input stream. + * No charset decoding is performed at this stage. + */ + public byte[] readFrame(InputStream in) throws IOException { ByteArrayOutputStream input = new ByteArrayOutputStream(256); - // todo define a maximum line length + long time = 0; int b; - while ((b = in.read()) != -1 && b != getEOL() && b != 0x0A && b != 0x0D) + while ((b = in.read()) != -1 && b != getEOL() && b != 0x0A && b != 0x0D && input.size() < MAX_SIZE) { - if (b != 0x0A && b != 0x0D) + input.write(b); + + if (input.size() == 1) { - input.write(b); + // let's start monitoring the input speed + time = System.currentTimeMillis(); } + else if (System.currentTimeMillis() - time > MAX_DELAY) + { + throw new IOException("Slow input detected (" + input.size() + " bytes over " + (System.currentTimeMillis() - time) + "ms)"); + } } if (b == -1) @@ -55,9 +72,19 @@ throw new IOException("End of stream"); } - return input.toString("ISO-8859-1"); + if (input.size() >= MAX_SIZE) + { + throw new IOException("Message frame exceeded the " + MAX_SIZE + " limit"); + } + + return input.toByteArray(); } + public String readLine(InputStream in) throws IOException + { + return new String(readFrame(in), "Cp1252"); + } + public boolean equals(Object o) { if (this == o) Modified: jetrix/trunk/src/test/net/jetrix/protocols/TetrinetProtocolTest.java =================================================================== --- jetrix/trunk/src/test/net/jetrix/protocols/TetrinetProtocolTest.java 2010-05-03 15:29:44 UTC (rev 846) +++ jetrix/trunk/src/test/net/jetrix/protocols/TetrinetProtocolTest.java 2010-05-03 18:13:52 UTC (rev 847) @@ -21,7 +21,9 @@ import static net.jetrix.protocols.TetrinetProtocol.*; +import java.io.*; import java.util.*; + import junit.framework.*; import net.jetrix.*; import net.jetrix.messages.channel.*; @@ -293,4 +295,44 @@ assertEquals("decoded", "tetrisstart Smanux 1.13", decode(init)); } + + public void testLongMessage() + { + byte[] message = new byte[16 * 1024]; + try + { + protocol.readLine(new ByteArrayInputStream(message, 0, message.length)); + fail("No exception raised on a 16K message"); + } + catch (IOException e) + { + // expected + } + } + + public void testSlowClient() + { + try + { + protocol.readLine(new InputStream() { + int i = 34; + public int read() throws IOException + { + try + { + Thread.sleep(1000); + } + catch (InterruptedException e) + { + } + return --i; + } + }); + fail("No exception raised on extremely slow input"); + } + catch (IOException e) + { + // expected + } + } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |