When performing an authenticated scan of your web application, the scan will usually require a GoScript to complete the authentication process. You can generate a GoScript automatically, or write one yourself.
To start, click GoScripts in the main menu, then New GoScript. You may be prompted to complete a GoScript creation wizard; if this doesn't appear automatically you can access it using the magic wand button:
Alternatively, if you don't wish to use the wizard, you can close it and write the script yourself.
Once the script is complete, save it, then return to your scan configuration and import it:
- Web Application Scanner Settings
- Authenticated Scanning
- Import GoScript
- Authenticated Scanning
If the scanner was able to pass and analyse the authentication barrier (either by generating its own script, or using a script you have provided) then your scan results will contains two Info level findings: "Successful Authentication" and "Successful Auth Analysis". If these do not appear and you have not written a script then you will need to write one. If these do not appear and you have written a script then the script is not sufficient, in this situation you may wish to contact AppCheck Support for further help.
You will need to be familiar with the basic commands described in A Guide to GoScript before proceeding.
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 relevant 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.
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
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).
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.
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.
Auth. Analysis
The purpose of your Authentication GoScript is to demonstrate a successful log-in and log-out flow to the scanner. Once the scanner has seen this, and is able to reproduce it, the next step is for the scanner to identify two crucial components:
- The Auth Mechanism - this is the process for submitting an authenticated request - this is usually a token (or tokens) that must be submitted in a request to make that request authenticated. This could be a header, a cookie, a URL parameter, or a combination. The scanner will determine this by observing requests made post-login (as demonstrated in your auth.confirm function), and testing those requests with components removed to see which are required to maintain the authenticated status.
- The Auth Indicator - this is an example authenticated request, one which will succeed if the session is still authenticated, and will fail otherwise (for example if we do not use the correct Auth Mechanism, or if the session has expired). This request is sent every ten seconds to confirm that the authenticated session is still active. This request will often be one seen during your auth.confirm function.
These components are essential in allowing the scanner to maintain an authenticated status in your application for the duration of the scan. Even if your login script completes successfully (as indicated by a "Successful Authentication" info level finding in the scan results), if the scanner is not able to determine the above components then the scan will not remain authenticated for its duration, so it is important that your scan results also contain a "Successful Auth Analysis" info level finding.
In this example you can see that the script completed successfully, but the analysis failed:
The GoScript development and testing tool at https://scanner.appcheck-ng.com/goscript/ allows you test the authentication analysis process independently of any scan (so you don't need to wait until a scan runs to find out if it will work).
To test authentication analysis for your script, follow these steps:
- Ensure the script itself completes successfully
-
Select the targets to be in scope for the test. These should be the targets you want to log in to, and should mirror the targets you intend to put in your scan once your script is finished.
- Then click this icon in the top bar:
The analysis will involve running the script multiple times and could take a couple of minutes to complete. Once finished the results will be shown on the Auth Profile tab:
It is important that you see an "Auth Detected" Analysis outcome, highlighted in green.
Username and Password Variables
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.
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 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 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.
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
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 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.