Loop/Architecture/Fingerprint Validation: Difference between revisions

From MozillaWiki
Jump to navigation Jump to search
Line 43: Line 43:


=== User Identification in a Room ===
=== User Identification in a Room ===
[[Loop/Architecture/Rooms#User Identification in a Room]]
This design expands the information defined by [[Loop/Architecture/Rooms#User Identification in a Room]] to include an array of PeerConnection fingerprints. Note that this array must be present (even when empty) if the client indicated a "fingerprint" feature when joining the room. It must not be present if the client didn't indicate support for "fingerprint".
 
  {
  {
     "displayName": "Alexis",
     "displayName": "-",
     "account": "alexis@example.com",
     "account": "alexis@example.com",
     "roomConnectionId": "2a1787a6-4a73-43b5-ae3e-906ec1e763cb",
     "roomConnectionId": "2a1787a6-4a73-43b5-ae3e-906ec1e763cb",

Revision as of 18:17, 24 September 2015

WebRTC's communications security model works by way of a three-pronged model:

  1. All media is encrypted with SRTP-DLTS, which uses a DH exchange to establish media security. The negotiated DH keys are not exposed to content.
  2. To prevent active on-path attacks, DTLS fingerprint validation is performed by using a third-party signature, rooted in the web PKI, to authenticate the fingerprint. See the WebRTC 1.0 Identity mechanism for details.
  3. To prevent in-content attacks, any streams for which fingerprint validation has been performed are "isolated" such that the content cannot be extracted by the webpage.

The first mechanism prevents passive interception; the second, active on-path interception; and the third, attacks by the content itself.

Currently, Hello makes use of only the first of these mechanisms, and relies on the security of the underlying network infrastructure (specifically, the OpenTok servers) to prevent on-path attacks. Because the nature of Hello does not require the use of any identity, making use of the second and third levels of protection can't be employed as specified.

It is worth noting that additional trust gained by adding the Identity mechanism is only as good as the trust provided by the party that is vouching for a user's identity. For example, if the corresponding service cannot be trusted to provide such certificates only to authenticated users (or cannot be trusted to properly validate certificates when asked to), then its role is largely defeated.

This basically sets up a system in which the Identity provider is serving as a third-party check against attacks on the infrastructure used to exchange SDP (and therefore DTLS fingerprints).

The design below provides additional protection by using Mozilla's servers to provide a third-party check against attacks on the OpenTok infrastructure, without requiring the use of verifiable user identities. Note that this isn't as strong as the protection provided by the WebRTC Identity mechanism; however, it is a significant improvement over the existing situation, as it would require attacks on both the OpenTok infrastructure and Mozilla's infrastructure to launch an active interception of content.

API Changes

This design proposes minimal changes to the Loop server protocol to allow clients to upload valid fingerprints for the room they are joining. At a high level, we expand the data maintained for a user in a room to include an array of fingerprints. Each fingerprint corresponds to an active PeerConnection associated with the room.

The following examples replace "displayName" with "-", as that is the behavior currently exhibited by the Hello client.

Joining a Room

For this scheme to work in a backwards-compatible fashion, the participants in a conversation need to know whether to expect their peers to be publishing fingerprints. For this, we add a simple capabilities announcement mechanism when users join a room. This is an additional parameter on the messages described at Loop/Architecture/Rooms#Joining a Room:

POST /rooms/QzBbvGmIZWU HTTP/1.1
Accept: application/json
Accept-Encoding: gzip, deflate
Content-Type: application/json; charset=utf-8
Authorization: <stripped>
Host: localhost:5000

{
    "action": "join",
    "displayName": "-",
    "clientMaxSize": 2,
    "features": ["fingerprint"]
}
  • features: An array of optional client behaviors that depend on the version of the client. Currently, only one value is defined:
    • fingerprint: Indicates support of the PeerConnection fingerprint validation mechanism. If this mechanism is present when the user joins a room, then the server must include a "fingerprints" array (which will initially be empty) as part of the user identification information. If absent, the server must not include such an array.

User Identification in a Room

This design expands the information defined by Loop/Architecture/Rooms#User Identification in a Room to include an array of PeerConnection fingerprints. Note that this array must be present (even when empty) if the client indicated a "fingerprint" feature when joining the room. It must not be present if the client didn't indicate support for "fingerprint".

{
    "displayName": "-",
    "account": "alexis@example.com",
    "roomConnectionId": "2a1787a6-4a73-43b5-ae3e-906ec1e763cb",
    "fingerprints": []
}
  • fingerprints: A list of "fingerprint" values associated with all the PeerConnections the client currently has in use. Only included if client included "fingerprint" in features array in "join"

Uploading Stream Fingerprints

Loop/Architecture/Rooms#Joining a Room

POST /rooms/QzBbvGmIZWU HTTP/1.1
Accept: application/json
Accept-Encoding: gzip, deflate
Content-Type: application/json; charset=utf-8
Authorization: <stripped>
Host: localhost:5000

{
    "action": "newpc",
    "fingerprint": "sha-256 15:E2:AF:50:91:87:FD:54:4C:82:F5:65:46:7A:84:D8:6C:53:00:99:C6:97:4E:64:2A:32:AA:A5:3C:91:E9:51"
}


Retrieving Room Information

Loop/Architecture/Rooms#GET_.2Frooms.2F.7Btoken.7D

HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 30
Content-Type: application/json; charset=utf-8
Date: Wed, 16 Jul 2014 13:23:04 GMT
ETag: W/"1e-2896316483"
Timestamp: 1405516984

{
    "roomToken": "3jKS_Els9IU",
    "roomName": "UX Discussion",
    "roomUrl": "http://localhost:3000/rooms/3jKS_Els9IU",
    "roomOwner": "Alexis",
    "maxSize": 2,
    "clientMaxSize": 2,
    "creationTime": 1405517546,
    "ctime": 1405517824,
    "expiresAt": 1405534180,
    "participants": [
       {
         "displayName": "Alexis",
         "account": "alexis@example.com",
         "roomConnectionId": "2a1787a6-4a73-43b5-ae3e-906ec1e763cb",
         "fingerprints": [
           "sha-256 15:E2:AF:50:91:87:FD:54:4C:82:F5:65:46:7A:84:D8:6C:53:00:99:C6:97:4E:64:2A:32:AA:A5:3C:91:E9:51",
           "sha-256 92:4B:E6:3C:DE:41:D6:F6:4A:F8:37:EC:44:3E:71:76:F3:4D:AC:7D:9C:21:6F:A9:37:5B:33:E5:9D:E2:7F:C0"
         ]
       },
       {
         "displayName": "Adam",
         "roomConnectionId": "781f012b-f1ea-4ce1-9105-7cfc36fb4ec7",
         "fingerprints": [
           "sha-256 87:C1:3C:5C:CB:D0:B6:86:3C:6E:A9:BF:CF:12:CD:F9:3F:37:95:B0:8C:3E:03:A1:6B:85:D7:B4:A4:22:1F:30",
           "sha-256 23:5E:B5:28:CF:2D:9F:D3:09:EE:E2:2F:D8:EF:DD:05:FA:FF:41:AB:1F:81:1F:73:21:E7:24:40:45:F1:8E:D4"
         ]
       }
     ]
}

Client Behavior

Roughly:

  • Monkeypatch setLocalDescription. When called:
    • POST new fingerprint to the room using "newpc" action
  • Monkeypatch setRemoteDescription. When called:
    1. Check list of fingerprints published by other person in the room
    2. If no match, perform a room GET to refresh information, and compare again
    3. If still no match, set a timer for 1 second; on expiry, try one more fetch and compare
    4. If still no match, error out the session and log an error to the server


Proof-of-Concept Monkeypatch Shim

(I presume this can be adapted to work with Chrome)

 window._originalRTCPeerConnection = window.mozRTCPeerConnection;
 
 window.mozRTCPeerConnection = function() {
   var setDescriptionShim = function(sdp, success, failure, pc, localRemote) {
     var fingerprint = /a=fingerprint:([^\r\n]*)/.exec(sdp.sdp)[1];
     console.log(localRemote + " fingerprint = " + fingerprint);
     pc["_originalSet" + localRemote + "Description"](sdp, success, failure);
   }
   var pc = new window._originalRTCPeerConnection();
   pc._originalSetLocalDescription = pc.setLocalDescription;
   pc._originalSetRemoteDescription = pc.setRemoteDescription;
   pc.setLocalDescription = function(sdp, success, failure) {
     setDescriptionShim(sdp, success, failure, pc, "Local");
   }
   pc.setRemoteDescription = function(sdp, success, failure) {
     setDescriptionShim(sdp, success, failure, pc, "Remote");
   }
   return pc;
 }