-
Notifications
You must be signed in to change notification settings - Fork 0
/
webAuth.als
232 lines (190 loc) · 6.29 KB
/
webAuth.als
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
open declarations
// Model the WebAuth Protocol
sig WAToken extends Token {}
// requester credentials
sig WAServiceToken extends WAToken { }
sig WAKrb5Token extends WAToken {}
// subject credentials
// The proxy token allow an application server to
// retrieve sensitive information (e.g. a user's
// mails or LDAP data) on behalf of the user.
sig WAProxyToken extends WAToken{}
sig WALoginToken extends WAToken{}
sig WACredToken extends WAToken{}
// request token
sig WARequestToken extends Token {}
sig WARequest extends Token {
msgId: lone Int
}
sig WAResponse extends Token {
causedByMsgId: lone Int
}
sig WAGetTokenReq extends WARequest {
reqCred:WAToken,
subjCred:lone WAToken,
reqToken:lone WARequestToken,
tokens:set WAToken
}
sig WASessionKey extends Secret {}
sig WAGetTokenResp extends WAResponse {
respTokens:set WAToken,
sessionKey:WASessionKey
}
sig WARequestTokenReq extends WARequest {
reqCred:WAServiceToken,
proxyTokens:set WAProxyToken,
loginTokens:WALoginToken,
reqToken:WARequestToken,
remoteUser:WebPrincipal
// optional IP addresses go here
}
sig WAErrorToken extends WAToken {}
sig WAAppToken extends WAToken {} // opaque application token
sig WARequestTokenResp extends WAResponse {
error:WAErrorToken,
proxyToken:lone WAProxyToken, // for login request
returnURL:URL,
requesterSubject:Principal, // identity of requester
subject:Principal, // identity in supplied credentials
requestedToken:lone WAIdToken+WAProxyToken,
loginCanceledToken:WAErrorToken,
appState:WAAppToken
}
sig WAProxyData extends WAToken {} // may contain encrypted Krb data
// This command converts an existing Kerberos token
// into a webkdc-proxy token, for improvied single sign-on.
sig WAProxyTokenReq extends WARequest {
subjCred:WAToken,
proxyData:WAProxyData
}
sig WAProxyTokenResp extends WAResponse {
proxyToken:WAProxyToken,
subject:WebPrincipal // identity from subject credential in the request
}
// This command extracts info from a proxy token
sig WAProxyTokenInfoReq extends WARequest {
proxyToken:WAProxyToken
}
sig WAProxyTokenInfoResp extends WAResponse {
subject:WebPrincipal, // identity from proxy token
// proxy type
creation:Time,
expiration:Time
}
sig WANonce extends Token {}
// HMAC used in WebAuth. We may move them to a generic crypto file after we accumulate enough of them
sig WAHmac extends Token {}
sig WAAttribute {name:Token, Value:Token}
sig WAEncryptedToken extends WAToken {
// 4-byte UTC time to tell the server which key was used to encrypt this token
private keyHint:Token,
private nonce:WANonce,
private hmac:WAHmac,
// private attrs:set WAAttribute,
private padding:Token
}
sig WAIdToken extends WAEncryptedToken{
private username: WebPrincipal,
// we don't need Kerberos subject authn data for now
private creationTime: Time,
private expirationTime: Time
}{
// Token should normally expire within 5 minutes based on WebAuth spec.
// Simulate using 5 ticks
expirationTime in creationTime.next.next.next.next.^next
}
pred WAContainsIdToken [resp:HTTPResponse, token:WAIdToken] {
one (LocationHeader & resp.headers) and
some locHdr: LocationHeader |
locHdr in resp.headers and
locHdr.targetPath in WASAuthPath and
token in locHdr.params.value
}
pred WAContainsIdToken [req:HTTPRequest, token:WAIdToken] {
token in req.queryString.value
}
pred WARemoteScriptingIsPossible {
1 = 1 // true unless user disables script support
}
sig WASAuthPath extends Path {}
sig WAS extends HTTPServer {}
sig WAWebKDC extends HTTPServer {}
pred WAPossessTokenViaLogin[httpClient:HTTPClient, token:WAIdToken, usageEvent:Event]{
some t1:HTTPTransaction|{
happensBeforeOrdering[t1.req, usageEvent] and
t1.req.path = LOGIN and
t1.req.to in WAWebKDC and
t1.req.from in httpClient and
t1.resp.statusCode in RedirectionStatus and
WAContainsIdToken[t1.resp, token] and
token.creationTime = t1.resp.post and
token.username in httpClient.owner
}
}
pred WAPossessTokenViaRemoteScripting [httpClient1:HTTPClient, token:WAIdToken, usageEvent:Event]{
// Through remote scripting, some user2(say, Mallory) can pass information to user1(say, Alice)'s browser
some t1:HTTPTransaction, httpClient2:HTTPClient|let user2=httpClient2.owner|
{
// Mallory possesses the token
WAPossessTokenViaLogin[httpClient2, token, usageEvent] and
// user1 (Alice) has a connection to user2(Mallory)'s web server
happensBefore[t1.req, usageEvent] and
t1.req.from in httpClient1 and
t1.req.to in (user2.servers & HTTPServer)
} and {
WARemoteScriptingIsPossible
}
}
fact WABeforeUsingTokenYouNeedToPossessIt{
all httpClient:HTTPClient, req:HTTPRequest, token:WAIdToken |
{
req.from in httpClient and
WAContainsIdToken [req, token]
} implies
WAPossessToken[httpClient, token, req]
}
pred WAPossessToken[httpClient:HTTPClient, token:WAIdToken, usageEvent:Event]{
WAPossessTokenViaLogin [httpClient, token, usageEvent] or
WAPossessTokenViaRemoteScripting [httpClient, token, usageEvent]
}
// Constrain the web model in this module for better illustration.
// The general model does not enforce this.
fact WAHTTPFacts{
all req:HTTPRequest | req.to in HTTPServer
all user:WebPrincipal | user.servers in HTTPServer
all t1:HTTPTransaction | some (t1.resp) implies (t1.req.from = t1.resp.to ) and (t1.req.to = t1.resp.from)
Mallory.servers in (HTTPServer - (WAS+WAWebKDC))
}
pred WALoginCSRF [t1:HTTPTransaction]{
some token:WAIdToken|{
t1.req.from in Alice.httpClients and
t1.req.path in WASAuthPath and
t1.req.to in WAS and
WAContainsIdToken [t1.req, token] and
token.username in Mallory
}
}
fun WAFindAttacks: HTTPTransaction{
{
t1:HTTPTransaction |
WALoginCSRF[t1]
}
}
// run WAFindAttacks for 8 but exactly 0 ACTIVEATTACKER, exactly 0 PASSIVEATTACKER
check WANoLoginCSRF {
no WAFindAttacks
}
for 8 but exactly 0 ACTIVEATTACKER, exactly 0 PASSIVEATTACKER
/*
Executing "Check WANoLoginCSRF for 8 but exactly 0 ACTIVEATTACKER, exactly 0 PASSIVEATTACKER"
Run 1:
====
Solver=minisat(jni) Bitwidth=4 MaxSeq=7 SkolemDepth=1 Symmetry=20
Generating CNF...
Generating the solution...
Begin solveAll()
194044 vars. 6761 primary vars. 386812 clauses. 601759ms.
Solving...
End solveAll()
Counterexample found. Assertion is invalid. 10889ms.
*/