Forcer tous les paramètres de cookies à Sécuriser dans ASP / VBScript classique

2020-07-29 php cookies https asp-classic

Je maintiens un ancien site Web écrit principalement en ASP / VBScript classique ( pas ASP.NET). Quand il a été écrit, HTTPS n'était pas encore vraiment une chose et tout sur le site était horriblement vulnérable lorsque j'ai pris le relais, mais j'ai depuis forcé HTTPS partout où je le pouvais.

Dans les versions les plus récentes de Firefox, j'ai reçu une multitude d'avertissements de console concernant les cookies lors de la visite du site:

Le cookie «XYZ» sera bientôt traité comme un cookie intersite contre «https://example.com/page.asp» car le schéma ne correspond pas.

Je suppose - bien que je n'ai pas pu trouver de confirmation - que c'est parce que les cookies définis par le serveur ne sont pas définis comme sécurisés, ce que je n'avais pas pris en compte lorsque j'ai déplacé le site vers HTTPS.

Alors maintenant, je dois tout changer pour que tous les cookies soient sécurisés. Le problème, c'est qu'une recherche rapide me dit qu'il y a environ 850 cookies définis dans environ 175 fichiers sur le serveur, et ... eh bien, je suis paresseux et je n'ai pas vraiment envie de parcourir 175 fichiers et d'ajouter Response.Cookies("XYZ").Secure = True 850 fois.

Existe-t-il un moyen de faire en sorte que le serveur (IIS, je suppose?) Force automatiquement tous les cookies à être définis comme sécurisés?

Edit: Une grande partie des choses les plus récentes que j'ai modifiées / construites / ajoutées au site Web se fait en PHP, juste pour éviter l'ASP classique. Je viens de remarquer que cette liste de cookies qui sont dits «bientôt traités comme cross-site» n'apparaît que sur les pages PHP, pas sur les pages ASP réelles. Alors peut-être que «le schéma ne correspond pas» ne concerne pas seulement HTTP vs HTTPS mais aussi ASP vs PHP d'une manière ou d'une autre? Comment m'assurer que les cookies définis dans ASP ne sont pas considérés comme intersites sur les pages PHP? Je ne pensais pas que le langage qui créerait les cookies ferait une différence car ce ne sont que des cookies en texte brut créés via une connexion HTTPS ...

Answers

Rendre le cookie de session sécurisé à l'aide de web.config:

Cette réécriture va changer:

ASPSESSIONIDXXXXXXXX=YYYYYYYYYYYYYYYYYYYYYYYY

dans:

__Secure-session=XXXXXXXX/YYYYYYYYYYYYYYYYYYYYYYYY

Non seulement cela sécurisera le cookie de session, mais cela éliminera le bogue ennuyeux que IIS semble avoir pour la configuration de plusieurs cookies ASPSESSIONIDXXXXXXXX. (Cela se produit parce que le nom du cookie de session n'est pas une constante, mais en en faisant une constante, en mettant toutes les données pertinentes à l'intérieur, puis en le réécrivant à l'aide d'une règle de réécriture entrante, vous n'aurez qu'un seul cookie de session sécurisée à la fois. )

<?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>

Vous pouvez probablement sécuriser tous les cookies en utilisant web.config, mais j'utilise une fonction:

<%

' 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>

Le sous-programme CreateCookies utilise des tableaux afin que vous puissiez définir plusieurs cookies à la fois:

Call CreateCookies(Array("cookie1","cookie2","cookie3"), Array("cookie1 value","cookie2 value","cookie3 value"), True, 90)

EDIT: Léger inconvénient à utiliser Response.AddHeader à Response.Cookies :

Lorsque vous utilisez Response.Cookies ce cookie est immédiatement disponible, ce qui signifie que vous pouvez utiliser Request.Cookies pour récupérer ce cookie à partir du cache du serveur lors du même chargement de page.

Alors:

Response.Cookies("test") = "test cookie"
Response.Write Request.Cookies("test")

Produira test cookie . Je ne peux pas vraiment comprendre pourquoi cela est utile, mais je me souviens vaguement de l'avoir utilisé dans le passé.

Avec:

Response.AddHeader "Set-Cookie","..."

Le cookie ne sera disponible à la lecture à l'aide de Request.Cookies lorsque la page est soumise à nouveau, mais bien sûr, vous avez BEAUCOUP plus de contrôle sur les paramètres des cookies. Ce n'est pas grave, mais cela vaut la peine d'être mentionné.

Related