Inject Multiple Cookies and Tokens
Overview
Sometimes authentication is not performed with just a username and password. For example, API key access or third-party authentication services like OAuth require custom tokens.
To support this type of authentication, HawkScan supports externally supplying authorization tokens with the authentication.external
configuration.
The authentication
section of the stackhawk.yml
will have 3 parts:
- Logged in/out indicators
- How HawkScan checks it is logged in throughout the scan.
- Auth(Z)
- Using
authentication.external
to tell HawkScan you will be injecting valid cookies or tokens for authorization
- Using
- Test Path
- How HawkScan sees if it successfully logged in
Make sure your file has all 3 of these parts filled out.
YAML for Injecting Credentials
Injecting Tokens:
stackhawk.yml
app:
applicationId: xxXXXXXX-xXXX-xxXX-XXxX-xXXxxXXXXxXX
env: Test
host: ${APP_HOST:http://localhost:3000}
authentication:
# Paths that HawkScan checks to see if it is still logged in during the scan
loggedInIndicator: "HTTP.*2[0-9][0-9]\\s*O[kK](\\s*)|HTTP.*3[0-9][0-9].*" # Change me
loggedOutIndicator: "HTTP.*4[0-9][0-9](\\s*)Unauthorized.*" # Change me
# Auth(Z) External Injection - this example will result in 2 request headers:
# Authorization: Bearer ${AUTH_TOKEN}
# AnotherToken: ${ANOTHER_TOKEN}
external:
values:
# Indicates whether the injected value is a cookie or token
- type: TOKEN
# If specified tokenType will be prepended the header value e.g. "Bearer xxxxxxxxx"
tokenType: Bearer
value:
# Name of the request header
name: Authorization
# Value of token
val: ${AUTH_TOKEN}
- type: TOKEN
value:
name: AnotherToken
val: ${ANOTHER_TOKEN}
# A path that can only be seen when successfully logged in. HawkScan will check this path to see if log in was successfull
testPath:
path: /mysettings
success: ".*200.*"
requestMethod: GET
Injecting Cookies:
stackhawk.yml
app:
applicationId: xxXXXXXX-xXXX-xxXX-XXxX-xXXxxXXXXxXX
env: Test
host: ${APP_HOST:http://localhost:3000}
authentication:
# Paths that HawkScan checks to see if it is still logged in during the scan
loggedInIndicator: "HTTP.*2[0-9][0-9]\\s*O[kK](\\s*)|HTTP.*3[0-9][0-9].*" # Change me
loggedOutIndicator: "HTTP.*4[0-9][0-9](\\s*)Unauthorized.*" # Change me
# Auth(Z) External Injection
external:
values:
# Indicates whether the injected value is a cookie or token
- type: COOKIE
value:
# Name of the cookie
name: JSESSIONID
# Value of the cookie
val: ${AUTH_COOKIE}
- type: COOKIE
value:
name: EXTRAID
val: ${ANOTHER_COOKIE}
# A path that can only be seen when successfully logged in. HawkScan will check this path to see if log in was successfull
testPath:
path: /login-multi-check #Change me
success: ".*200.*"
requestMethod: GET
YAML Sections in Detail
Injecting Authorization with .external
The first half of your authentication
section in your stackhawk.yml
will be to tell HawkScan you are using an externally supplied authorization.
The .values
will be a list off cookies or header tokens or both that will be injected into each request that StackHawk sends to the application.
For the .type
of TOKEN
, headers are added to each request in this format “.name:
.tokenType .val
”.
For the .type
of COOKIE
, cookes are added to wach request in this format “Cookie: .name
=.val
”.
Values for tokens and cookies will need to be added at run time either in your run command or as stored secrets.
We do not recommend adding it directly to your stackhawk.yml
file.
This is both for security reasons, but also to avoid errors if the token expires.
stackhawk.yml
app:
applicationId: xxXXXXXX-xXXX-xxXX-XXxX-xXXxxXXXXxXX
env: Test
host: ${APP_HOST:http://localhost:3000}
authentication:
loggedInIndicator: "\\QLog out\\E"
loggedOutIndicator: "\\QLog in\\E"
external:
values:
- type: COOKIE
value:
name: JSESSIONID
val: ${AUTH_COOKIE}
- type: TOKEN
tokenType: Bearer
value:
name: Authorization
val: ${AUTH_TOKEN}
testPath:
path: /authenticated/path
success: '.*200.*'
Maintaining the Session
Unlike other authentication types, the session is maintained by injecting the headers and cookies into each request as indicated in the stackhawk.yml
.
Test Paths and Logged In/Out Indicators
No matter what type of Authorization/Authentication your app is using, HawkScan requires .testPath
, .loggedInIndicator
and .loggedOutIndicator
.
Test Path:
A testPath
configuration needs to be provided to verify HawkScan authenticated its session correctly before scanning the application.
The testPath
configuration also provides requestMethod
and requestBody
options to support alternate HTTP request verbs, such as POST
or PUT
.
The default action is GET
.
Your testPath
should be a path that HawkScan can only access when successfully logged in.
This could be a path like “/dashboard” or “/accountdetails”
stackhawk.yml
app:
applicationId: xxXXXXXX-xXXX-xxXX-XXxX-xXXxxXXXXxXX
env: Test
host: ${APP_HOST:http://localhost:3000}
authentication:
loggedInIndicator: "\\QLog out\\E"
loggedOutIndicator: "\\QLog in\\E"
testPath:
path: /login-multi-check
success: ".*200.*"
requestMethod: GET
Logged In/Out Indicators
Throughout the scan, HawkScan will check to see if it is still logged in by the .loggedInIndicator
and .loggedOutIndicator
.
These are regex strings to match against http responses from requests in the web application.
A .loggedInIndicator
could be a “Log Out” or ”Sign Out” button a user would see if logged in.
An example of a .loggedOutIndicator
would be a “Log In” button on the sign in page.
These can also leverage http status codes from the response.
stackhawk.yml
app:
applicationId: xxXXXXXX-xXXX-xxXX-XXxX-xXXxxXXXXxXX
env: Test
host: ${APP_HOST:http://localhost:3000}
authentication:
loggedInIndicator: "HTTP.*2[0-9][0-9]\\s*O[kK](\\s*)|HTTP.*3[0-9][0-9].*"
loggedOutIndicator: "HTTP.*4[0-9][0-9](\\s*)Unauthorized.*"
testPath:
path: /authenticated/path
success: '.*200.*'
Example Multiple External Cookie Authorization
This scenario will use the following route layout.
GET /login-code
GET /login-form-multi
POST /login-form-multi
GET /login-multi-check <- protected route
Detailed Configuration
You would want a stackhawk.yml
configuration like this.
stackhawk.yml
app:
applicationId: xxXXXXXX-xXXX-xxXX-XXxX-xXXxxXXXXxXX
env: Test
host: ${APP_HOST:http://localhost:3000}
authentication:
loggedInIndicator: "HTTP.*2[0-9][0-9]\\s*O[kK](\\s*)|HTTP.*3[0-9][0-9].*"
loggedOutIndicator: "HTTP.*4[0-9][0-9](\\s*)Unauthorized.*"
external:
values:
- type: COOKIE
value:
name: "XLOGINID"
val: ${XLOGINID}
- type: COOKIE
value:
name: "JSESSIONID"
val: ${JSESSIONID}
testPath:
path: /login-multi-check
success: ".*200.*"
requestMethod: GET
In the above configuration we are specifying .external.values[0].val=${XLOGINID}
and .external.values[0].val=${JSESSIONID}
to allow the authorization cookies to be passed in as an environment variable at runtime.
Now create a script to generate the authorization cookies. This is an example using a customized route in the javaspringvulny project to generate a session cookie and a login cookie as well as parsing and saving the _csrf
token. It logs in the user and then runs hawk scan with those cookie values passed as environment variables.
#!/usr/bin/env bash
# Request login (XLOGINID) and session (JSESSIONID) cookies from server and saves them to the cookie-jar.txt file.
curl -c cookie-jar.txt https://localhost:9000/login-code
# Parses cookie-jar.txt file to get the JSESSIONID.
JSESSIONID=$(awk 'match($0, /JSESSIONID.*/){print substr($0, RSTART + 11, RLENGTH)}' cookie-jar.txt )
# Parses cookie-jar.txt file to get the XLOGINID.
XLOGINID=$(awk 'match($0, /XLOGINID.*/){print substr($0, RSTART + 9, RLENGTH)}' cookie-jar.txt)
# Request page with cookie-jar.txt cookies and extract the _csrf token from the response
CSRF=$(curl -b cookie-jar.txt \
https://localhost:9000/login-form-multi | awk 'match($0,/_csrf".*/) { print substr($0, RSTART+14, RLENGTH -17)}')
# Log into the mutli cookie endpoint using XLOGINID and JSESSIONID cookies (stored in cookie-jar.txt) and username/password.
# This example also uses the XLONGID as a paremeter passed to the server in the request body.
curl -v -k \
-d "_csrf=${CSRF}&loginCode=${XLOGINID}&username=user&password=password&remember=on" \
-b cookie-jar.txt \
-H "Content-Type: application/x-www-form-urlencoded" \
"https://localhost:9000/login-form-multi"
# Run HawkScan injecting local variables as environment variables
hawk scan -e JSESSIONID=${JSESSIONID} -e XLOGINID=${XLOGINID}
Authorized GET Request to /login-multi-check
GET /login-multi-check HTTP/1.1
Host: localhost:9000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/114.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Cookie: JSESSIONID=CDDC53E08070E78BF0A8C8F240B2157E; XLOGINID=a30c2167-87c4-4905-9554-66e58a64289c