Skip to content

Commit 6c7c60d

Browse files
Phil Kulakcodebutler
authored andcommitted
Validate Handshake Response
Make sure that the server response includes a Sec-WebSocket-Accept header and that it's what it should be.
1 parent 29eeccd commit 6c7c60d

File tree

1 file changed

+28
-2
lines changed

1 file changed

+28
-2
lines changed

src/main/java/com/codebutler/android_websockets/WebSocketClient.java

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.net.Socket;
2323
import java.net.URI;
2424
import java.security.KeyManagementException;
25+
import java.security.MessageDigest;
2526
import java.security.NoSuchAlgorithmException;
2627
import java.util.List;
2728

@@ -69,6 +70,8 @@ public void connect() {
6970
@Override
7071
public void run() {
7172
try {
73+
String secret = createSecret();
74+
7275
int port = (mURI.getPort() != -1) ? mURI.getPort() : (mURI.getScheme().equals("wss") ? 443 : 80);
7376

7477
String path = TextUtils.isEmpty(mURI.getPath()) ? "/" : mURI.getPath();
@@ -88,7 +91,7 @@ public void run() {
8891
out.print("Connection: Upgrade\r\n");
8992
out.print("Host: " + mURI.getHost() + "\r\n");
9093
out.print("Origin: " + origin.toString() + "\r\n");
91-
out.print("Sec-WebSocket-Key: " + createSecret() + "\r\n");
94+
out.print("Sec-WebSocket-Key: " + secret + "\r\n");
9295
out.print("Sec-WebSocket-Version: 13\r\n");
9396
if (mExtraHeaders != null) {
9497
for (NameValuePair pair : mExtraHeaders) {
@@ -110,13 +113,26 @@ public void run() {
110113

111114
// Read HTTP response headers.
112115
String line;
116+
boolean validated = false;
117+
113118
while (!TextUtils.isEmpty(line = readLine(stream))) {
114119
Header header = parseHeader(line);
115120
if (header.getName().equals("Sec-WebSocket-Accept")) {
116-
// FIXME: Verify the response...
121+
String expected = createSecretValidation(secret);
122+
String actual = header.getValue().trim();
123+
124+
if (!expected.equals(actual)) {
125+
throw new HttpException("Bad Sec-WebSocket-Accept header value.");
126+
}
127+
128+
validated = true;
117129
}
118130
}
119131

132+
if (!validated) {
133+
throw new HttpException("No Sec-WebSocket-Accept header.");
134+
}
135+
120136
mListener.onConnect();
121137

122138
// Now decode websocket frames.
@@ -203,6 +219,16 @@ private String createSecret() {
203219
return Base64.encodeToString(nonce, Base64.DEFAULT).trim();
204220
}
205221

222+
private String createSecretValidation(String secret) {
223+
try {
224+
MessageDigest md = MessageDigest.getInstance("SHA-1");
225+
md.update((secret + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11").getBytes());
226+
return Base64.encodeToString(md.digest(), Base64.DEFAULT).trim();
227+
} catch (NoSuchAlgorithmException e) {
228+
throw new RuntimeException(e);
229+
}
230+
}
231+
206232
void sendFrame(final byte[] frame) {
207233
mHandler.post(new Runnable() {
208234
@Override

0 commit comments

Comments
 (0)