Forum Discussion
Confusing ASP.NET session cookie rewriting with HttpOnly flag version 10
Hi Everyone, first post here so a little introduction.
I am a sysadmin/developer for a large insurance company and have just taken ownership of our F5 box. 12 Years IT experience so I can usually figure stuff out.. But not today.
We have been flagged on a pentest recently that we are not adding the Secure flag and HttpOnly flag to our cookies. Our site is very diverse so getting all the devlopment depts up to speed is a challange.
So I should be able to do this with an Irule right? (V10 so no HTTP::cookie HttpOnly "name" Enable, I can't use that) Well, I have a working solution, but I'd like some help on the behaviour described below:
Using Ncat on backtrack to see the raw traffic this is a standard response from the server for a .NET session: (No rule manipulation at this point)
-------------------------------------------------------------------------------------
user@bt:~ ncat mydomain.com 443 --ssl
HEAD /test.aspx HTTP/1.1
Host:mydomain.com
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 21216
Content-Type: text/html; charset=utf-8
Expires: -1
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Set-Cookie: ASP.NET_SessionId=d4or5si4ezfo3oiienjmzjug; path=/; HttpOnly
Date: Wed, 02 Jan 2013 15:26:51 GMT
-------------------------------------------------------------------------------------
OK so we have a pretty standard server response here.
Now when I write the following Irule Code:
when HTTP_RESPONSE {
set myValues [HTTP::cookie names]
foreach mycookies $myValues {
set currentValue [HTTP::cookie $mycookies]
HTTP::cookie remove $mycookies
HTTP::header insert "Set-Cookie" "$mycookies=$currentValue; HttpOnly; Secure; Path=/;"
}
}
This code seems simple enough, get a list of cookie names. Loop through them. Extract the value of the cookie. Delete it, recreate from stored name and value with the required flags. What I get is this:
-------------------------------------------------------------------------------------
X-AspNet-Version: 2.0.50727
Set-Cookie: HttpOnly
Date: Web, 02 Jan 2013 15:36:14 GMT
Set-Cookie: ASP.NET_SessionId=qmalso4555a4bjbuspcgsj55
Set-Cookie: HttpOnly=; HttpOnly; Secure; Path=/;
----------------------------------------------------------------------------------------
Errr OK, I now have 3 cookies? and two are called "HttpOnly"? This seems rather odd, lets do some debugging. It appears to be looping twice even though there is one cookie. So Ill add some header inserts as debug statements to show where I am in the loop:
when HTTP_RESPONSE {
set myValues [HTTP::cookie names]
foreach mycookies $myValues {
HTTP::header insert "Test" $mycookies
set currentValue [HTTP::cookie $mycookies]
HTTP::cookie remove $mycookies
HTTP::header insert "Set-Cookie" "$mycookies=$currentValue; HttpOnly; Secure; Path=/;"
}
}
So a header called test should print out everytime the loop is hit...
Response:
-------------------------------------------------------------------------------------
X-AspNet-Version: 2.0.50727
Set-Cookie: HttpOnly
Date: Web, 02 Jan 2013 15:41:14 GMT
Test: ASP.NET_SessionId
Set-Cookie: ASP.NET_SessionId=pwkwy1452plfijbhlqqtre45
Test: HttpOnly
Set-Cookie: HttpOnly=; HttpOnly; Secure; Path=/;
-------------------------------------------------------------------------------------
OK this is curious. We are looping twice for sure as the Test header appears twice and it seems that its seeing the HttpOnly flag as a cookie???? Also, Why has that Set-Cookie appeared ABOVE the timestamp????
What is going on here? Have I fundamentally misunderstood this programing language? Well since we are looping twice, lets force it to skip the second loop:
when HTTP_RESPONSE {
set myValues [HTTP::cookie names]
foreach mycookies $myValues {
if {$mycookies == "HttpOnly"} {
donothing DO NOT REMOVE THIS LINE!
}
else {
set currentValue [HTTP::cookie $mycookies]
HTTP::cookie remove $mycookies
HTTP::header insert "Set-Cookie" "$mycookies=$currentValue; HttpOnly; Secure; Path=/;"
}
}
}
Lets see what we get now:
-------------------------------------------------------------------------------------
X-AspNet-Version: 2.0.50727
Set-Cookie: HttpOnly
Date: Web, 02 Jan 2013 15:41:14 GMT
Set-Cookie: ASP.NET_SessionId=fc403oqe1aneu4fxcokdfup; HttpOnly; Secure; Path=/;
-------------------------------------------------------------------------------------
Wait a minute....wat? OK so the header insert for the session cookie now works. But we still have this mysterious extra Set-Cookie: HttpOnly. Where and why is this happening?
Now doing a little research I discovered that all .NET session cookies come with the HttpOnly flag by default and cannot be changed in IIS to remove this. OK that means I don't have to add the flag at all, infact I can use the built in "secure" function in HTTP::cookie, Great!
when HTTP_RESPONSE {
set myValues [HTTP::cookie names]
foreach mycookies $myValues {
switch $mycookies {
"ASP.NET_SessionId" {
HTTP::cookie secure "ASP.NET_SessionId" enable
}
default {
set currentValue [HTTP::cookie $mycookies]
if {$mycookies == "HttpOnly"} {
donothing DO NOT REMOVE THIS LINE!
}
else {
HTTP::cookie remove $mycookies
HTTP::header insert "Set-Cookie" "$mycookies=$currentValue; HttpOnly; Secure; Path=/"
}
}
}
}
}
So the above will loop through all cookies, check if the name is ASPNET etc and ONLY add the secure flag. Any other cookie will be rewritten and deleted.
This works fine for the .NET session cookie. All other cookies seem to work fine too, but I still get the odd "Set-Cookie: HttpOnly" for any other cookie thats being rewritten here alway appearing above the date field.
I have now fully tested this with session cookies from ASP.NET, standard ASP (VB6), and custom written cookies. The above code seems to work fine in all situations.
So my real question is... Am I a complete idiot and have missed something obvious here... or does this code loop twice for one cookie and seems to think that the HttpOnly flag is a cookie?
OK now add multiple cookies:
If I have 2 or more cookies AND add a HTTP::cookie remove "HttpOnly" statement to the code, behaviour gets odd depending where. If its in the httponly if statement, the first cookie that gets written has only its name and value (Like above). If its after the loop, the LAST Set-Cookie has the flags removed and only its name and value. In both these scenarios it seems to think that httponly is a cookie name and not a flag.
I'm guessing here that this is a v10 bug thats fixed in v11?
7 Replies
- nitass
Employee
what about this one?[root@ve10:Active] config b virtual bar80 list virtual bar80 { snat automap pool foo destination 172.28.19.252:80 ip protocol 6 rules myrule profiles { http {} tcp {} } } [root@ve10:Active] config b pool foo list pool foo { members 200.200.200.101:80 {} } [root@ve10:Active] config b rule myrule list rule myrule { when HTTP_RESPONSE { set myValues [HTTP::header values "Set-Cookie"] HTTP::header remove "Set-Cookie" foreach mycookies $myValues { scan [lindex $mycookies 0] {%[^=]=%[^;]} currentName currentValue HTTP::header insert "Set-Cookie" "$currentName=$currentValue; HttpOnly; Secure; Path=/" } } } response from server (not passing bigip) [root@ve10:Active] config curl -I http://200.200.200.101 HTTP/1.1 200 OK Cache-Control: no-cache Pragma: no-cache Content-Length: 21216 Content-Type: text/html; charset=utf-8 Expires: -1 X-Powered-By: ASP.NET X-AspNet-Version: 2.0.50727 Set-Cookie: ASP.NET_SessionId=d4or5si4ezfo3oiienjmzjug; path=/; HttpOnly Set-Cookie: testcookie=123456; path=/ Set-Cookie: mycookie=abcdef; path=/; HttpOnly Date: Wed, 02 Jan 2013 15:26:51 GMT response from bigip [root@centos251 ~] curl -I http://172.28.19.252 HTTP/1.1 200 OK Cache-Control: no-cache Pragma: no-cache Content-Length: 21216 Content-Type: text/html; charset=utf-8 Expires: -1 X-Powered-By: ASP.NET X-AspNet-Version: 2.0.50727 Date: Wed, 02 Jan 2013 15:26:51 GMT Set-Cookie: ASP.NET_SessionId=d4or5si4ezfo3oiienjmzjug; HttpOnly; Secure; Path=/ Set-Cookie: testcookie=123456; HttpOnly; Secure; Path=/ Set-Cookie: mycookie=abcdef; HttpOnly; Secure; Path=/
- nitass
Employee
your 1st irule seems working fine in 11.3.0.root@(ve11a)(cfg-sync Changes Pending)(Active)(/Common)(tmos) show sys version Sys::Version Main Package Product BIG-IP Version 11.3.0 Build 2806.0 Edition Final Date Tue Nov 13 22:34:00 PST 2012 root@(ve11a)(cfg-sync Changes Pending)(Active)(/Common)(tmos) list ltm virtual bar ltm virtual bar { destination 172.28.20.14:80 ip-protocol tcp mask 255.255.255.255 pool foo profiles { http { } tcp { } } rules { myrule } source 0.0.0.0/0 source-address-translation { type automap } vlans-disabled } root@(ve11a)(cfg-sync Changes Pending)(Active)(/Common)(tmos) list ltm pool foo ltm pool foo { members { 200.200.200.101:80 { address 200.200.200.101 } } } root@(ve11a)(cfg-sync Changes Pending)(Active)(/Common)(tmos) list ltm rule myrule ltm rule myrule { when HTTP_RESPONSE { set myValues [HTTP::cookie names] foreach mycookies $myValues { set currentValue [HTTP::cookie $mycookies] HTTP::cookie remove $mycookies HTTP::header insert "Set-Cookie" "$mycookies=$currentValue; HttpOnly; Secure; Path=/;" } } } response from server (not passing bigip) [root@ve11a:Active:Changes Pending] config curl -I http://200.200.200.101 HTTP/1.1 200 OK Cache-Control: no-cache Pragma: no-cache Content-Length: 21216 Content-Type: text/html; charset=utf-8 Expires: -1 X-Powered-By: ASP.NET X-AspNet-Version: 2.0.50727 Set-Cookie: ASP.NET_SessionId=d4or5si4ezfo3oiienjmzjug; path=/; HttpOnly Set-Cookie: testcookie=123456; path=/ Set-Cookie: mycookie=abcdef; path=/; HttpOnly Date: Wed, 02 Jan 2013 15:26:51 GMT response from bigip [root@centos251 ~] curl -I http://172.28.20.14 HTTP/1.1 200 OK Cache-Control: no-cache Pragma: no-cache Content-Length: 21216 Content-Type: text/html; charset=utf-8 Expires: -1 X-Powered-By: ASP.NET X-AspNet-Version: 2.0.50727 Date: Wed, 02 Jan 2013 15:26:51 GMT Set-Cookie: testcookie=123456; HttpOnly; Secure; Path=/; Set-Cookie: ASP.NET_SessionId=d4or5si4ezfo3oiienjmzjug; HttpOnly; Secure; Path=/; Set-Cookie: mycookie=abcdef; HttpOnly; Secure; Path=/;
- Stefan_126426
Nimbostratus
Hi Nitass - Stefan_126426
Nimbostratus
Ahhh, begining to see: - nitass
Employee
[root@ve10:Active] config b rule myrule list rule myrule { when HTTP_RESPONSE { set myValues [HTTP::header values "Set-Cookie"] log local0. "myValues: $myValues" HTTP::header remove "Set-Cookie" foreach mycookies $myValues { log local0. "-----" log local0. "mycookies: $mycookies" log local0. "\[lindex $mycookies 0\]: [lindex $mycookies 0]" log local0. "scan \[lindex $mycookies 0\] {%\[^=\]=%\[^;\]} currentName currentValue: [scan [lindex $mycookies 0] {%[^=]=%[^;]} currentName currentValue]" log local0. "currentName: $currentName" log local0. "currentValue: $currentValue" scan [lindex $mycookies 0] {%[^=]=%[^;]} currentName currentValue HTTP::header insert "Set-Cookie" "$currentName=$currentValue; HttpOnly; Secure; Path=/" } } } client [root@centos251 ~] curl -I http://172.28.19.252 HTTP/1.1 200 OK Cache-Control: no-cache Pragma: no-cache Content-Length: 21216 Content-Type: text/html; charset=utf-8 Expires: -1 X-Powered-By: ASP.NET X-AspNet-Version: 2.0.50727 Date: Wed, 02 Jan 2013 15:26:51 GMT Set-Cookie: ASP.NET_SessionId=d4or5si4ezfo3oiienjmzjug; HttpOnly; Secure; Path=/ Set-Cookie: testcookie=123456; HttpOnly; Secure; Path=/ Set-Cookie: mycookie=abcdef; HttpOnly; Secure; Path=/ log on bigip [root@ve10:Active] config tail -f /var/log/ltm Jan 4 08:10:03 local/tmm info tmm[4876]: Rule myrule : myValues: {ASP.NET_SessionId=d4or5si4ezfo3oiienjmzjug; path=/; HttpOnly} {testcookie=123456; path=/} {mycookie=abcdef; path=/; HttpOnly} Jan 4 08:10:03 local/tmm info tmm[4876]: Rule myrule : ----- Jan 4 08:10:03 local/tmm info tmm[4876]: Rule myrule : mycookies: ASP.NET_SessionId=d4or5si4ezfo3oiienjmzjug; path=/; HttpOnly Jan 4 08:10:03 local/tmm info tmm[4876]: Rule myrule : [lindex ASP.NET_SessionId=d4or5si4ezfo3oiienjmzjug; path=/; HttpOnly 0]: ASP.NET_SessionId=d4or5si4ezfo3oiienjmzjug; Jan 4 08:10:03 local/tmm info tmm[4876]: Rule myrule : scan [lindex ASP.NET_SessionId=d4or5si4ezfo3oiienjmzjug; path=/; HttpOnly 0] {%[^=]=%[^;]} currentName currentValue: 2 Jan 4 08:10:03 local/tmm info tmm[4876]: Rule myrule : currentName: ASP.NET_SessionId Jan 4 08:10:03 local/tmm info tmm[4876]: Rule myrule : currentValue: d4or5si4ezfo3oiienjmzjug Jan 4 08:10:03 local/tmm info tmm[4876]: Rule myrule : ----- Jan 4 08:10:03 local/tmm info tmm[4876]: Rule myrule : mycookies: testcookie=123456; path=/ Jan 4 08:10:03 local/tmm info tmm[4876]: Rule myrule : [lindex testcookie=123456; path=/ 0]: testcookie=123456; Jan 4 08:10:03 local/tmm info tmm[4876]: Rule myrule : scan [lindex testcookie=123456; path=/ 0] {%[^=]=%[^;]} currentName currentValue: 2 Jan 4 08:10:03 local/tmm info tmm[4876]: Rule myrule : currentName: testcookie Jan 4 08:10:03 local/tmm info tmm[4876]: Rule myrule : currentValue: 123456 Jan 4 08:10:03 local/tmm info tmm[4876]: Rule myrule : ----- Jan 4 08:10:03 local/tmm info tmm[4876]: Rule myrule : mycookies: mycookie=abcdef; path=/; HttpOnly Jan 4 08:10:03 local/tmm info tmm[4876]: Rule myrule : [lindex mycookie=abcdef; path=/; HttpOnly 0]: mycookie=abcdef; Jan 4 08:10:03 local/tmm info tmm[4876]: Rule myrule : scan [lindex mycookie=abcdef; path=/; HttpOnly 0] {%[^=]=%[^;]} currentName currentValue: 2 Jan 4 08:10:03 local/tmm info tmm[4876]: Rule myrule : currentName: mycookie Jan 4 08:10:03 local/tmm info tmm[4876]: Rule myrule : currentValue: abcdef
- Stefan_126426
Nimbostratus
It does indeed, many thanks. - Stefan_126426
Nimbostratus
This is my final version as I needed to exlude some cookies from being manipulated. Hopefully someone may find it useful
Recent Discussions
Related Content
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com