When performing an authenticated scan of your web application you will often need to write a GoScript to tell the scanner how to log in to your application. Sometimes the scanner can work out how to log in without a script, so you may wish to run a scan with no script (just a username and password) first, then check to see if your scan results show an Info level finding called "Successful Authentication". If they do not (as is common with modern web applications) then a script is needed.
Note: You will need to be familiar with the basic commands described in A Guide to GoScript before proceeding.
Note: If your application uses TOTP or email based One Time Password (OTP) Multi-Factor Authentication (MFA) then you should read this guide first, then proceed to the relevent OTP guide in our Advanced GoScript section.
Contents
See also: Selecting an Account for your Authenticated Web Application Scan
Outline
A standard Authentication GoScript contains three functions, auth.login, auth.confirm, and auth.logout.
auth.login
auth.login is used to authenticate with the application, beginning an authenticated session. It should end with a "wait for:" command that looks for a string that appears once authentication has completed. If that string does not appear, the script will fail, and the scanner will know that authentication was not successful.
A common pattern for a login function is:
- Go to the login page.
- Enter the username.
- Enter the password (you might need to submit the username first, if the boxes are on different pages).
- Submit.
- Wait for a string that confirms we are logged in.
- Click on to another page that can only be accessed when authenticated.
- Wait for a string that appears on that page.
The last two steps are to confirm that the authenticated session is working, and to demonstrate to the scanner what authenticated requests look like (ie requests made after the authentication process has completed - until that point it has only seen requests made during the authentication process). This is important to help the scanner make artificial authenticated requests as part of its testing process.
IMPORTANT: if you are scanning an API alongside the front end application, make sure the thing you click for step 6 is something that triggers an API request - the scanner needs to witness an authenticated API request so that it can make its own such requests in order to scan the API.
auth.confirm
auth.confirm is run periodically to confirm that the authenticated session is still alive. Like auth.login, it should end with a "wait for:" command that looks for a string that appears only when in an authenticated session. If that string does not appear, the script will fail, and the scanner will know that it needs to log in again.
A common pattern for a confirm function is:
- Go to a page that can only be accessed when authenticated.
- Wait for a string that appears on that page.
auth.logout
Note: This function can be left out if your application does not provide logout functionality.
auth.logout is used to end an authenticated session.; This is used in various scan processes to test the authentication system (and can help keep the number of open sessions recorded server-side to a minimum).
Note: This function is also useful if your application only supports a single (or limited number) of active sessions per user and will prevent further logins if that number of active sessions is reached. In such a case you will also need to configure your scan to run in a single thread to avoid concurrent logins. It would be preferable to remove this limit so you can run the scan multi-threaded.
This function should end with a "wait for:" command that looks for a string that appears after successfully logging out (often this will be a string on the login page).
A common pattern for a logout function is:
- Click your application's menu or profile button to expand the menu, revealing a log out button.
- Click the revealed log out button.
- Wait for a string that appears after logging out, often this will be a string on the login page.
IMPORTANT: Your auth functions must each end with a "wait for:" command. The "wait for:" command fails if the given string is not seen - this is how the scanner knows that the login process failed. Without this check the scanner will think it is logged in when it is not.
Username and Password Variables
Note: see GoScript Variables for an introduction to variables.
The scanner passes a number of variables into authentication GoScripts, including the username and password supplied in the scan configuration. This means you can avoid hardcoding the username and password into the script, which is more secure (since scripts are printed to logs on the scan hubs) and easier to maintain (since the username and password can be changed independently of the script).
The examples below use these variables, using the {variableName} syntax.
IMPORTANT: You must fill in the Username and Password fields in your scan configuration, even if you do not actually refer to the variables in your script. If you do not fill in these fields the authentication system may not run.
Basic Access Authentication
If you application only uses Basic Access Authentication then you do not need a GoScript, see Scanning a Web Application That Uses Basic Access Authentication.
If your application uses Basic Access Authentication in conjunction with another access control mechanism then you will need to use a GoScript in addition to the Basic Access Authentication header.
You can include your Basic Access Authentication header in the GoScript editing/testing interface like so:
The header will be sent with all requests both during the execution of the GoScript and, if added to a scan, during scanning.
The header will be added to your scan configuration when you import to GoScript.
Examples
Basic Example
def auth.login
# Go to the login page and wait for it to load
go: https://www.example.com/
wait for: Forgot password?
# Submit our credentials and wait for the next page to load
username = {username}
password = {password}
click: Login
wait for: My Account
click: My Account
wait for: Change address
# If "Change address" does not appear on the page then the login has failed
def auth.confirm
go: https://www.example.com
wait for: My Account
click: My Account
wait for: Change address
# If "Change address" does not appear on the page then we have failed to confirm
# that we are still logged in, so the scanner will run auth.login again
def auth.logout
click: menu
wait for: logout
# We do not need a "go:" command here because the menu button on this
# site is always visible, whatever page the browser is on. Instead we
# just click the menu button then wait for the logout button to appear.
click: logout
wait for: Forgot password?
# When we see the login page again we know we've successfully logged out.
Note: Some applications, particularly Single Page Applications (SPAs), use data submitted with each request to maintain the session, so navigating to a page using the browser's address bar will log you out. In these situations avoid using go: commands - instead look for an element which always appears and click: it. This is often the company logo in the top left, which might take you back to a dashboard for example, and this can be used to confirm you're still logged in:
def auth.confirm
click: #company_logo
wait for: My Account
click: My Account
wait for: Change address
# In this example if the GoScript engine cannot click an element
# with ID company_logo (because it isn't there), or if clicking
# it does not take us to a page containing "My Account" (and so on)
# then the function fails, and the GoScript engine knows it is logged
# out and that it should run auth.login again.
Advanced auth.login Example Using Conditional Logic
This example uses conditional logic to handle a situation where the login process changes after the first visit. See Conditionals for a guide to using conditional login in GoScripts.
def auth.login
go: https://www.example.com
if see {username}
click: {username}
else
wait for: Forgot password?
username = {username}
# The above conditional logic clicks the user's name if it appears,
# otherwise it types the user's name into the username box. In
# either case, it then carries on to the next step.
password = {password}
click: Login
wait for: My Account
click: My Account
wait for: Change address
# The above "wait for:" command will time out if "Change address" does not
# appear on the page within 30 seconds. This counts as an authentication
# failure.
# If any commands earlier in the script fail or time out that also counts
# as an authentication failure.
Comments
0 comments
Article is closed for comments.