WSTG - Stable
Testing for Credentials Transported over an Encrypted Channel
Testing for credentials transport verifies that web applications encrypt authentication data in transit. This encryption prevents attackers from taking over accounts by sniffing network traffic. Web applications use HTTPS to encrypt information in transit for both client to server and server to client communications. A client can send or receive authentication data during the following interactions:
- A client sends a credential to request login
- The server responds to a successful login with a session token
- An authenticated client sends a session token to request sensitive information from the web site
- A client sends a token to the web site if they forgot their password
Failure to encrypt any of these credentials in transit can allow attackers with network sniffing tools to view credentials and possibly use them to steal a user’s account. The attacker could sniff traffic directly using Wireshark or similar tools, or they could set up a proxy to capture HTTP requests. Sensitive data should be encrypted in transit to prevent this.
The fact that traffic is encrypted does not necessarily mean that it’s completely safe. The security also depends on the encryption algorithm used and the robustness of the keys that the application is using. See Testing for Weak Transport Layer Security to verify the encryption algorithm is sufficient.
- Assess whether any use case of the web site or application causes the server or the client to exchange credentials without encryption.
How to Test
To test for credential transport, capture traffic between a client and web application server that needs credentials. Check for credentials transferred during login and while using the application with a valid session. To set up for the test:
- Set up and start a tool to capture traffic, such as one of the following:
- The web browser’s developer tools
- A proxy including OWASP ZAP
- Disable any features or plugins that make the web browser favour HTTPS. Some browsers or extensions, such as HTTPS Everywhere, will combat forced browsing by redirecting HTTP requests to HTTPS.
In the captured traffic, look for sensitive data including the following:
- Passphrases or passwords, usually inside a message body
- Tokens, usually inside cookies
- Account or password reset codes
For any message containing this sensitive data, verify the exchange occurred using HTTPS (and not HTTP). The following examples show captured data that indicate passed or failed tests, where the web application is on a server called
Find the address of the login page and attempt to switch the protocol to HTTP. For example, the URL for the forced browsing could look like the following:
If the login page is normally HTTPS, attempt to remove the “S” to see if the login page loads as HTTP.
Log in using a valid account while attempting to force the use of unencrypted HTTP. In a passing test, the login request should be HTTPS:
Request URL: https://www.example.org/j_acegi_security_check Request method: POST ... Response headers: HTTP/1.1 302 Found Server: nginx/1.19.2 Date: Tue, 29 Sep 2020 00:59:04 GMT Transfer-Encoding: chunked Connection: keep-alive X-Content-Type-Options: nosniff Expires: Thu, 01 Jan 1970 00:00:00 GMT Set-Cookie: JSESSIONID.a7731d09=node01ai3by8hip0g71kh3ced41pmqf4.node0; Path=/; Secure; HttpOnly ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE=dXNlcmFiYzoxNjAyNTUwNzQ0NDU3OjFmNDlmYTZhOGI1YTZkYTYxNDIwYWVmNmM0OTI1OGFhODA3Y2ZmMjg4MDM3YjcwODdmN2I2NjMwOWIyMDU3NTc=; Path=/; Expires=Tue, 13-Oct-2020 00:59:04 GMT; Max-Age=1209600; Secure; HttpOnly Location: https://www.example.org/ ... POST data: j_username=userabc j_password=My-Protected-Password-452 from=/ Submit=Sign in
- In the login, the credentials are encrypted due to the HTTPS request URL
- If the server returns cookie information for a session token, the cookie should also include the
Secureattribute to avoid the client exposing the cookie over unencrypted channels later. Look for the
Securekeyword in the response header.
The test fails if any login transfers a credential over HTTP, similar to the following:
Request URL: http://www.example.org/j_acegi_security_check Request method: POST ... POST data: j_username=userabc j_password=My-Protected-Password-452 from=/ Submit=Sign in
In this failing test example:
- The fetch URL is
http://and it exposes the plaintext
j_passwordthrough the post data.
- In this case, since the test already shows POST data exposing all the credentials, there is no point checking response headers (which would also likely expose a session token or cookie).
To test for unencrypted account creation, attempt to force browse to the HTTP version of the account creation and create an account, for example:
The test passes if even after the forced browsing, the client still sends the new account request through HTTPS:
Request URL: https://www.example.org/securityRealm/createAccount Request method: POST ... Response headers: HTTP/1.1 200 OK Server: nginx/1.19.2 Date: Tue, 29 Sep 2020 01:11:50 GMT Content-Type: text/html;charset=utf-8 Content-Length: 3139 Connection: keep-alive X-Content-Type-Options: nosniff Set-Cookie: JSESSIONID.a7731d09=node011yew1ltrsh1x1k3m6g6b44tip8.node0; Path=/; Secure; HttpOnly Expires: 0 Cache-Control: no-cache,no-store,must-revalidate X-Hudson-Theme: default Referrer-Policy: same-origin Cross-Origin-Opener-Policy: same-origin X-Hudson: 1.395 X-Jenkins: 2.257 X-Jenkins-Session: 4551da08 X-Hudson-CLI-Port: 50000 X-Jenkins-CLI-Port: 50000 X-Jenkins-CLI2-Port: 50000 X-Frame-Options: sameorigin Content-Encoding: gzip X-Instance-Identity: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3344ru7RK0jgdpKs3cfrBy2tteYI1laGpbP4fr5zOx2b/1OEvbVioU5UbtfIUHruD9N7jBG+KG4pcWfUiXdLp2skrBYsXBfiwUDA8Wam3wSbJWTmPfSRiIu4dsfIedj0bYX5zJSa6QPLxYolaKtBP4vEnP6lBFqW2vMuzaN6QGReAxM4NKWTijFtpxjchyLQ2o+K5mSEJQIWDIqhv1sKxdM9zkb6pW/rI1deJJMSih66les5kXgbH2fnO7Fz6di88jT1tAHoaXWkPM9X0EbklkHPT9b7RVXziOURXVIPUTU5u+LYGkNavEb+bdPmsD94elD/cf5ZqdGNoOAE5AYS0QIDAQAB ... POST data: username=user456 fullname=User 456 password1=My-Protected-Password-808 password2=My-Protected-Password-808 Submit=Create account Jenkins-Crumb=58e6f084fd29ea4fe570c31f1d89436a0578ef4d282c1bbe03ffac0e8ad8efd6
- Similar to a login, most web applications automatically give a session token on a successful account creation. If there is a
Set-Cookie:, verify it has a
Secure;attribute as well.
The test fails if the client sends a new account request with unencrypted HTTP:
Request URL: http://www.example.org/securityRealm/createAccount Request method: POST ... POST data: username=user456 fullname=User 456 password1=My-Protected-Password-808 password2=My-Protected-Password-808 Submit=Create account Jenkins-Crumb=8c96276321420cdbe032c6de141ef556cab03d91b25ba60be8fd3d034549cdd3
- This Jenkins user creation form exposed all the new user details (name, full name, and password) in POST data to the HTTP create account page
Password Reset, Change Password or Other Account Manipulation
Similar to login and account creation, if the web application has features that allow a user to change an account or call a different service with credentials, verify all of those interactions are HTTPS. The interactions to test include the following:
- Forms that allow users to handle a forgotten password or other credential
- Forms that allow users to edit credentials
- Forms that require the user to authenticate with another provider (for example, payment processing)
Accessing Resources While Logged In
After logging in, access all the features of the application, including public features that do not necessarily require a login to access. Forced browse to the HTTP version of the web site to see if the client leaks credentials.
The test passes if all interactions send the session token over HTTPS similar to the following example:
Request URL:http://www.example.org/ Request method:GET ... Request headers: GET / HTTP/1.1 Host: www.example.org User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate, br DNT: 1 Connection: keep-alive Cookie: JSESSIONID.a7731d09=node01ai3by8hip0g71kh3ced41pmqf4.node0; ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE=dXNlcmFiYzoxNjAyNTUwNzQ0NDU3OjFmNDlmYTZhOGI1YTZkYTYxNDIwYWVmNmM0OTI1OGFhODA3Y2ZmMjg4MDM3YjcwODdmN2I2NjMwOWIyMDU3NTc=; screenResolution=1920x1200 Upgrade-Insecure-Requests: 1
- The session token in the cookie is encrypted since the request URL is HTTPS
The test fails if the browser submits a session token over HTTP in any part of the web site, even if forced browsing is required to trigger this case:
Request URL:http://www.example.org/ Request method:GET ... Request headers: GET / HTTP/1.1 Host: www.example.org User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Cookie: language=en; welcomebanner_status=dismiss; cookieconsent_status=dismiss; screenResolution=1920x1200; JSESSIONID.c1e7b45b=node01warjbpki6icgxkn0arjbivo84.node0 Upgrade-Insecure-Requests: 1
- The GET request exposed the session token
JSESSIONID(from browser to server) in request URL
Use HTTPS for the whole web site. Implement HSTS and redirect any HTTP to HTTPS. The site gains the following benefits from using HTTPS for all its features:
- It avoids losing customers to insecure site warnings. New browsers mark HTTP based web sites as insecure.
- It makes writing certain applications easier. For example, Android APIs need overrides to connect to anything via HTTP.
If it is cumbersome to switch to HTTPS, prioritize HTTPS for sensitive operations first. For the medium term, plan to convert the whole application to HTTPS to avoid losing customers to compromise or the warnings of HTTP being insecure. If the organization does not already buy certificates for HTTPS, look in to Let’s Encrypt or other free certificate authorities on the server.