Making the session cookie secure using web.config:
This rewrite will change:
ASPSESSIONIDXXXXXXXX=YYYYYYYYYYYYYYYYYYYYYYYY
into:
__Secure-session=XXXXXXXX/YYYYYYYYYYYYYYYYYYYYYYYY
Not only will it make the session cookie secure, but it eliminates the annoying bug IIS seems to have for setting multiple ASPSESSIONIDXXXXXXXX cookies. (This occurs because the session cookie name is not a constant, but by making it a constant, putting all the relevant data inside, then rewriting it back using an inbound rewrite rule, you'll only have one secure session cookie at a time.)
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<clear />
<!-- "HTTP_COOKIE" must be added to the "allowed server variables" in IIS under URLRewrite -->
<rule name="session cookie revert">
<match url="(.*)" />
<conditions>
<add input="{HTTP_COOKIE}" pattern="(.*)__Secure-session=([0-9a-zA-Z]+)\/([0-9a-zA-Z]+)(.*)" />
</conditions>
<serverVariables>
<set name="HTTP_COOKIE" value="{C:1}ASPSESSIONID{C:2}={C:3}{C:4}" />
</serverVariables>
<action type="None" />
</rule>
</rules>
<outboundRules>
<rule name="session cookie rewrite">
<match serverVariable="RESPONSE_Set_Cookie" pattern="ASPSESSIONID([0-9a-zA-Z]+)=([0-9a-zA-Z]+)(.*)" negate="false" />
<!-- Set the session cookie as HttpOnly during the rewrite. Classic ASP doesn't
do this by default, but it's important for preventing XSS cookie stealing.
You could also add "; Secure" if you only want the session cookie to be passed
over an SSL connection, although this also means the cookie can only be set over
an SSL connection too, which could be a problem when testing on localhost. -->
<action type="Rewrite" value="__Secure-session={R:1}/{R:2}{R:3}; SameSite=None; HttpOnly; Secure" />
</rule>
</outboundRules>
</rewrite>
<httpProtocol>
<customHeaders>
<add name="X-Frame-Options" value="SAMEORIGIN" />
<add name="X-Content-Type-Options" value="nosniff" />
<add name="X-XSS-Protection" value="1; mode=block" />
<add name="Referrer-Policy" value="strict-origin" />
<add name="Strict-Transport-Security" value="max-age=31536000" />
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>
You could probably make all cookies secure using web.config, but I use a function:
<%
' Create cookies.
Sub CreateCookies(ByVal NameArray, ByVal DataArray, HttpOnly, ExpireDays)
Dim CookieStr, CookieExpires, i
' Validate the array parameters.
If NOT IsArray(NameArray) OR NOT IsArray(DataArray) Then Exit Sub
If NOT uBound(NameArray) = uBound(DataArray) Then Exit Sub
' Set the cookie expiration date.
CookieExpires = CookieExperationDate(ExpireDays)
' If HttpOnly is true...
If HttpOnly Then CookieStr = "HttpOnly; "
' If the https protocol is being used, set the cookie as secure.
If uCase(Request.ServerVariables("HTTPS")) = "ON" Then
CookieStr = CookieStr & "Secure; "
End If
' Loop through the cookies array and set each cookie.
' Both the name and value should be encoded using the
' Server.URLEncode() function before being passed, if
' necessary (usually not, unless your name/data values
' contain characters like ";" or "=")
For i = 0 To uBound(NameArray)
Response.AddHeader "Set-Cookie",NameArray(i) & "=" & DataArray(i) & "; Path=/; SameSite=None; " & CookieStr & CookieExpires
Next
End Sub
' Deletes all cookies, can easily be changed to delete individual cookies though
Sub DeleteCookies()
Dim Item
' There isn't a header command for deleting a cookie, instead, you
' set the expiration date to a time that has already expired, and
' the users browser will automatically delete the cookie.
Const CookieDeleteDate = "Expires=Thu, 01 Jan 1970 00:00:00 UTC"
' Loop through each cookie and set a header to delete it.
' NOTE: Request.Cookies doesn't retrieve session cookies, at least
' not the ASP session cookie.
For Each Item In Request.Cookies
If NOT InStr(Item,"_") = 1 Then ' For avoiding deleting Google analytics and Cloudflare cookies, plus any cookie beginning with an underscore usually indicates it's some sort of third party cookie.
Response.AddHeader "Set-Cookie",Item & "=; Path=/; " & CookieDeleteDate
End If
Next
End Sub
' Generate and format the cookie expiration date
Function CookieExperationDate(ExpireDays)
Dim UTCtime, ActualLCID
' Get the current UTC time.
UTCtime = UTC_DateTime()
' Change the LCID to 1033 as to be RFC 6265 compliant.
ActualLCID = Response.LCID
Response.LCID = 1033
UTCtime = DateAdd("d",ExpireDays,UTCtime)
' Format the cookie experation date
CookieExperationDate = "Expires=" &_
WeekDayName(WeekDay(UTCtime),True) & ", " &_
ZeroPad(Day(UTCtime)) & " " &_
MonthName(Month(UTCtime),True) & " " &_
Year(UTCtime) & " " &_
"00:00:00 UTC"
' Change the LCID back to what it originally was.
Response.LCID = ActualLCID
End Function
' Prefix numbers less than 10 with a 0, (01,02,03 etc...) this is used for cookie date formating
Function ZeroPad(ByVal theNumber)
ZeroPad = theNumber
If Len(theNumber) = 1 Then
ZeroPad = cStr("0" & theNumber)
End If
End Function
%>
<script language="javascript" type="text/javascript" runat="server">
// Return the current UTC date and time regardless of what timezone the server is set to
function UTC_DateTime() {
var date = new Date();
// date.getUTCMonth() returns a value from 0 - 11 (dunno why) so we need to + 1
var result = date.getUTCFullYear() + "-" + (date.getUTCMonth() + 1) + "-" + date.getUTCDate() + " " + date.getUTCHours() + ":" + date.getUTCMinutes() + ":" + date.getUTCSeconds();
// Pad month/day/hour/minute/second values with a 0 If necessary
return result.replace(/(\D)(\d)(?!\d)/g, "$10$2");
}
</script>
The CreateCookies sub uses arrays so you can set multiple cookies at once:
Call CreateCookies(Array("cookie1","cookie2","cookie3"), Array("cookie1 value","cookie2 value","cookie3 value"), True, 90)
EDIT: Slight downside to using Response.AddHeader to Response.Cookies:
When you use Response.Cookies that cookie is immediately available, which means you can use Request.Cookies to fetch that cookie from the server cache on the same page load.
So:
Response.Cookies("test") = "test cookie"
Response.Write Request.Cookies("test")
Will output test cookie. I can't really think why this is useful, but I do vaguely recall using it in the past.
With:
Response.AddHeader "Set-Cookie","..."
The cookie will only be available to read using Request.Cookies when the page is resubmitted, but of course you have MUCH more control over the cookie settings. Not a big deal, but worth mentioning.
Secure = Truewould have been a one-line change. - user692942Response.Cookie("XYZ") = "abc"with function calls. - Janus Bahs JacquetSecurenorSameSiteis set in them, but they are set and read through secure connections on the same site. - Janus Bahs Jacquet