GoScript is a scripting language that can be used to describe browser interactions, and is an advanced feature unique to AppCheck, combining the power of automated scanning with the guidance of a human to step through complex user journeys and processes.
GoScript can be used to model complex journeys in order to test deep into the application and access screened application portions (such as areas that require authentication).
Some example uses include:
-
Authenticating the scanner in your application, including Single Sign On (SSO) and some (but not all) Multi-Factor Authentication (MFA) solutions.
-
Navigating complex flows involving multiple stages, forms or screens, navigating them like a user would, eg sign-up flows; purchases/shopping cart journeys.
- Submitting forms that require specific, known input, which the scanner would be unlikely to guess (eg the user must type a valid ID number).
-
Improving scanning of single page applications by going through targeted processes as opposed to clicking blindly.
How GoScript Works
A GoScript is a series of commands, one per line. Most commands take the form:
[instruction]: [target element]
eg
click: Add to Basket
In this example the GoScript engine will try to identify an element on the current page matching the text "Add to Basket" using various identifiers including the element's ID, name, label, content, adjacent text, etc. If you have the text "Add to Basket" next to a button the GoScript engine will assume it's the button, not the next, that you want to click.
It will then click on that element.
This matching process isn't perfect, and sometimes the GoScript engine will not find the element you're after. In these cases, or if you simply want to be very specific, you can use a full selector to specify the target element, eg
click: #some_objects > span:nth-child(2) > i:nth-child(1)
Tip: You can get a selector for an element by selecting it in your web browser's Developer Tools -> Inspector then selecting Copy -> Selector (the exact name of this option varies between browsers)
Note: Some instructions, such as the equals (=) instruction, have the target on the left hand side. In this case you cannot use a selector starting with a hash (#) since the line would then be interpreted as a comment
Example
This example uses the scanned application's search facility to locate an item, select it and add it to the shopping basket.
# Search for a specific book go: http://www.amazon.co.uk/ searchtextbox = Grey hat hacking book 3rd click: Go # Go to the book's product page wait for: the ethical hackers handbook click: Gray Hat Hacking The Ethical Hackers Handbook, 3rd Edition wait for: Thwart malicious network intrusion by using cutting-edge # Add it to our basket click: Add to Basket wait for: Added to basket # Begin checkout process click: Proceed to checkout wait for: Create your Amazon account email = test@tesing.com password = Password123
# End of example
Tip: You can insert blank lines to make your script easier to read - this will have no effect on how the script runs. I like to use blank lines to break up a script into logical sections.
Commands
Instruction |
Description |
Examples |
# |
A line beginning with # is a comment. This is used for adding notes to a GoScript and has no effect when the GoScript runs. |
#This is a comment. It has no effect when the GoScript runs.
|
go: |
Tell the browser to go directly to the given URL as though by entering it into the address bar (ie not by interacting with any element on the existing page) |
go: http://www.example.com |
wait for: |
Wait for a given string to appear on the page |
wait for: Welcome |
pause: |
Wait a given number of seconds |
pause: 15 |
= |
Set the value of a field. You can use {username} and {password} to access the credentials set in the scan configurations. Note: Spacing is important - make sure you include a space on either side of the = as shown in the examples. |
#This example includes the username directly within the script. #This example uses the {} placeholder, and therefore imports the |
click: |
Find a page element and trigger a click |
#This example uses the text "Log In" which could match various attributes #This example uses a selector which uniquely identifies a specific element. |
press: |
Press the specified key |
press: enter |
type: |
Press a series of keys, useful for entering text and triggering listeners |
type: QWERTY |
js: |
Run the following JavaScript |
js: document.getElementsByClassName('form-control')[0].value = 'test'; |
Conditionals
In certain complex situations you may need to use conditionals in your GoScript, so that part of the script is only executed if a certain condition is met. A (somewhat) common example of this is a login process where you are presented with a different login screen depending on the presence or lack of certain cookies, so your GoScript needs to follow one process on the first visit and a different process on subsequent visits within the same browser session.
The code following the condition should be indented. Once the indentation stops the condition has ended and further commands will be run regardless of the condition.
Instruction |
Description |
Examples |
if see |
If the text following "if see" is found on the page within the timeout period (usually 30 seconds) then the following indented code is executed. Note: There is no punctuation in this command: do not use a colon as you would in a "wait for" command, and do not place quote marks around the string you are checking for. |
if see Some text that might appear on the page If the string "Some text that might appear on the page" is seen within the timeout period the script proceeds to load https://puppies.com, otherwise it continues to the next line |
elif see |
The same as an "if see" command, but only runs if the proceeding "if see" condition was false (ie the specified string was not seen). Note: The script will wait for the timeout for each "if see" and "elif see" until one is found, so can end up with quite a long pause if you have several conditions and none, or a later one, is seen. |
if see Some text that might appear on the page If the string "Some text that might appear on the page" is seen within the timeout period the script loads https://puppies.com. If that was not seen, but "Some different text" is seen, the script loads https://kittens.com. |
else |
If the proceeding "if see" statement (and any "elif see" statements, if present) was false then the following indented code is executed. |
if see Some text that might appear on the page If the string "Some text that might appear on the page" is seen within the timeout period the script loads https://puppies.com. If that was not seen, but "Some different text" is seen, the script loads https://kittens.com. If neither was seen the script loads https://www.seeturtles.org/. Note: Although the code executed under each condition are all single lines in the above example they do not need to be: you could have several lines of code under each condition, indicated by them being indented, eg: ... |
IMPORTANT: Conditional statements are not currently supported in the GoScript testing interface at https://scanner.appcheck-ng.com/goscript, though they work correctly during scans. Our developers are working on this, but in the meantime if you need to test a script containing a conditional please raise a ticket with Technical Support.
Authentication GoScripts
An Authentication GoScript contains twoa functionsfunction, auth.login and auth.confirm. Use the keyword "def" and the name of the function to begin it, and then indent the function contents. When you stop indenting, you've ended that function. Tip: the example below should make this clearer.
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.
{username} and {password} can be used instead of storing the actual credentials in the script. These placeholders will be replaced with the credentials from the scan configuration at runtime. This is good practice and allows you to share/re-use scripts without sharing credentials.
Basic Example:
def auth.login
go: https://www.website.com
wait for: Forgot password?
username = {username}
password = {password}
click: Login
wait for: My Account
# The above "wait for" command will time out if "My Account" does not
# appear on the page within 30 seconds. This counts as an authentication
# failure.
# If any wait for commands earlier in the script time out that also counts
# as an authentication failure.
def auth.confirm
go: https://www.website.com
wait for: My Account
# The above "wait for" command will time out if "My Account" does not
# appear on the page within 30 seconds. This tells the scanner that
# it needs to run auth.login again
Tip: The first line of auth.login is often go: to the target site's root URL, and the last line is often wait for: a string which appears only when logged in. That's what we need to do to test whether we're still logged in! That means these two lines can often be re-used for the auth.confirm function, as seen in the example above. This is a common pattern.
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 Dashboard
# In this example if the GoScript engine cannot see an element with
# ID company_logo, or if clicking it does not take us to a page
# containing "My Dashboard", then the function fails, and the
# GoScript engine knows it is logged out and that it should run
# auth.login again.
Example using conditional logic, where the login screen changes after the first visit:
def auth.login
go: https://www.website.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
password = {password}
click: Login
wait for: My Account
# The above "wait for" command will time out if "My Account" does not
# appear on the page within 30 seconds. This counts as an authentication
# failure.
# If any wait for commands earlier in the script time out that also counts
# as an authentication failure.
# IMPORTANT: Conditional statements are not currently supported in the
# GoScript testing interface at https://scanner.appcheck-ng.com/goscript,
# though they work correctly during scans. Our developers are working on
# this, but in the meantime if you need to test a script containing a
# conditional please raise a ticket with Technical Support.
Saving and Testing GoScripts
You can write, test and save your scripts at https://scanner.appcheck-ng.com/goscript.
Once it is verified as working you can import the script into a scan configuration using the Import GoScript button in the Authenticated Scanning section (for Authentication Scripts) or the Advanced Settings section (for workflow GoScripts) of the Web Application Scanner Settings (or just copy-paste it into the appropriate box).
When testing the script it will be marked as Passed if no component failed. If writing an authentication script you want it to fail if it was not able to log in, so you should "wait for:" a string that only appears when logged in - the tester will time out (and fail) if that string does not appear in 30 seconds. It's a good idea to test the script with the wrong credentials to confirm this works as expected.
There are two things to be aware of when developing your script:
- You must save (and then re-open) your script before clicking Test Script. If you click Test Script without saving first it will run the last saved version of the script.
- When you import a script into a scan the scan now has its own copy of the script. Changes made at /goscript will not alter the version saved in the scan.
Note: The GoScript testing interface at https://scanner.appcheck-ng.com/goscript does not support the placeholders {username} and {password}. You will need to include the values in full within the scripts when testing.
Comments
0 comments
Please sign in to leave a comment.