ソースを参照

validate tokens in a way that timing attacks are not possible

David Luhmer 6 年 前
コミット
0234e8097f

+ 1 - 1
src/main/java/com/nextcloud/android/sso/InputStreamBinder.java

@@ -210,6 +210,6 @@ public class InputStreamBinder extends IInputStreamService.Stub {
     private boolean isValid(NextcloudRequest request) {
     private boolean isValid(NextcloudRequest request) {
         SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
         SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
         String storedToken = sharedPreferences.getString(request.packageName, "");
         String storedToken = sharedPreferences.getString(request.packageName, "");
-        return validPackages.contains(request.packageName) && request.token.equals(storedToken);
+        return request.validateToken(storedToken);
     }
     }
 }
 }

+ 20 - 3
src/main/java/com/nextcloud/android/sso/aidl/NextcloudRequest.java

@@ -37,9 +37,7 @@ public class NextcloudRequest implements Serializable {
     public String packageName;
     public String packageName;
     public String accountName;
     public String accountName;
 
 
-    private NextcloudRequest() {
-
-    }
+    private NextcloudRequest() { }
 
 
     public static class Builder {
     public static class Builder {
         private NextcloudRequest ncr;
         private NextcloudRequest ncr;
@@ -92,4 +90,23 @@ public class NextcloudRequest implements Serializable {
             return this;
             return this;
         }
         }
     }
     }
+
+    public boolean validateToken(String token) {
+        // As discussed with Lukas R. at the Nextcloud Conf 2018, always compare whole strings
+        // and don't exit prematurely if the string does not match anymore to prevent timing-attacks
+        return isEqual(this.token.getBytes(), token.getBytes());
+    }
+
+    // Taken from http://codahale.com/a-lesson-in-timing-attacks/
+    private static boolean isEqual(byte[] a, byte[] b) {
+        if (a.length != b.length) {
+            return false;
+        }
+
+        int result = 0;
+        for (int i = 0; i < a.length; i++) {
+            result |= a[i] ^ b[i];
+        }
+        return result == 0;
+    }
 }
 }