One of the most important qualities of a professional web application vulnerability scanner is the ability to reach every part of the web application, including the protected areas. While many scanners struggle with this, Acunetix supports several authentication mechanisms and offers an easy way to record logins. In this article, we want to show you how to use Acunetix to scan an application that uses Google OAuth 2.0 authentication.
This guide is divided into three parts:
- Part 1. Create a Google project for the web application
- Part 2. Create the web application
- Part 3. Scan the web application
Part 1. Create a Google Project for the Web Application
Our example application requires a Google project to use Google OAuth 2.0 authentication. To create the Google project, do the following steps:
- Go to the Google Cloud Platform dashboard
- Click on the Create project button
- Set the project name (here: AX-example) and click on the Create button
- Go to APIs & Services → OAuth consent screen
- Set the User Type to External and click on the Create button to proceed to the OAuth consent screen
- In the App information section, provide:
- The name you wish to give to your app
- The email address that will receive support requests for issues relating to your app
- The logo you wish to give to your app
- In the App domain section, provide:
- The URL for the home page for your application
- The URL for the privacy policy page for your application
- The URL for the terms of service page for your application
- The list of authorized domains – typically this will contain any domains related to the above 3 URLs
- In the Developer contact information section:
- Provide the email address for Google to send developer-related information and notifications to
- Click on the Save and continue button to continue to the Scopes part of the app registration process
- In the Scopes screen, click on the Add or remove scopes button
- In the Update selected scopes popup, select the scopes your application requires; typically you would start with the email, the profile, and the openid
- Scroll to the bottom of the popup and click on the Update button to confirm your selected scopes
- Next, scroll to the bottom of the Scopes page and click on the Save and continue button to proceed to the Test users page
- While you are still testing your app (prior to app verification), you must add the test users that will be allowed access to the app
- When done adding test users, click on the Save and continue button at the bottom of the page to proceed to the summary screen; scroll to the bottom of the summary screen and click on the Back to Dashboard button
- Next, go to the Google Search Console
- In the URL prefix panel, enter the URL prefix for your domain and click on the Continue button
- Next, you need to verify ownership of the website; there are several ownership verification methods available – in this example, we have chosen to download a verification file to upload to our website
- Click on the filename to download the file, upload it to the root of your website, and click on the Verify button
- Click on the Done button to end the Domain Verification process
- Back on the APIs & Services page in the Google Cloud Platform, click on the Domain verification menu option
- Click on the Add domain button
- Enter your domain name and click on the Add domain button
- Your Domain verification page will now show your domain in the Allowed domains list
- Back on the APIs & Services page in the Google Cloud Platform, click on the Credentials menu option
- Click on the Create credentials button and select OAuth client ID from the dropdown
- On the Create OAuth client ID page:
- Set the Application type to Web application
- Set the Application name to a friendly name; in this example, we are using AX Example Web Application
- Add an Authorized redirect URI; in this example, we are using https://acunetixexample.com/google_redirect.php
- Click on the Create button
- The summary screen will present you with the Client ID and Client Secret for your app; You will need to use these values in your web application
Part 2. Create the Web Application
Step 1. Install Libraries
Using a Bash terminal, go to your website folder, for example:
cd /var/www/html
and install the required library:
composer require google/apiclient
Step 2. Create the Website Content
Our example website is a very simple document library.
Using a Bash terminal, go to your website folder, for example:
cd /var/www/html
and create a simple document library:
mkdir library
cd library
echo "dummy content" > chapter_01.txt
tee <chapter_01.txt chapter_{02..40}.txt >/dev/null
Step 3. Install the Database Table
Using a MySQL terminal, enter the following commands:
CREATE DATABASE oa2;
CREATE USER 'oa2'@'localhost' identified by 'oa2pass';
USE oa2;
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(30) DEFAULT NULL,
`email` varchar(30) DEFAULT NULL,
`login` tinyint(4) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `unique_email` (`email`)
);
Step 4. Build the Website Code
- Create the index.php file:
<?php include 'config.php'; require_once 'functions.php'; session_start(); if (session_id() == '' || !isset($_SESSION) || $_SESSION['useremail'] == '') { write_log("index.php || No session in catfile.php. Sending to error.php"); kill_session(); echo "<h1>No user is logged in at this time</h1><br><br>"; } elseif (!function_response(user_exists($_SESSION['useremail'])) == 200) { write_log("index.php || Session user " . $_SESSION['useremail'] . "invalid in catfile.php. Destroying session and sending to error.php"); kill_session(); echo "<h1>No user is logged in at this time</h1><br><br>"; } elseif (!function_response(user_login_status($_SESSION['useremail'])) == 200) { write_log("index.php || Session user " . $_SESSION['useremail'] . "not logged-in in catfile.php. Destroying session and sending to error.php"); kill_session(); echo "<h1>No user is logged in at this time</h1><br><br>"; } else { write_log("index.php || Valid Logged-In User with email: <" . $_SESSION['useremail'] . ">."); write_log("index.php || session_id():" . session_id()); write_log("index.php || SESSION['useremail']" . $_SESSION['useremail']); echo "<h1>User Logged in: " . $_SESSION['useremail'] . "</h1><br><br>"; } ?> <a href='/google_redirect.php'>Google Login Page</a><br> <a href='/catfile.php'>Document Library</a><br> <a href='/logout.php'>Logout</a><br>
- Create the config.php file:
<?php $db_host = 'localhost'; $db_name = 'oa2'; $db_user = 'oa2'; $db_pass = 'oa2pass'; $file_log = 'oa2.log'; $base_folder = '/var/www/html'; $google_clientID = '529752975297-6vd1obh4acfaulls6vd1obh4acfaulls.apps.googleusercontent.com'; $google_clientSecret = 'uN5DK0ZduN5DK0ZduN5DK0Zd'; $google_redirectUri = 'https://acunetixexample.com/google_redirect.php'; ?>
Note the following:
- $google_clientID should contain your own Google client ID
- $google_clientSecret should contain your own Google client secret
- $google_redirectUri should reflect your own domain name instead of acunetixexample.com
- Create the functions.php file:
<?php include 'config.php'; function function_response($response_string) : int { $response_value = intval(substr($response_string,0,3)); return $response_value; } function function_payload($response_string) : string { $response_value = substr($response_string,4); return $response_value; } function db_connect() : string { global $db_host, $db_user, $db_pass, $db_name, $db_conn; if ($db_conn==null) { try { $db_conn = new PDO("mysql:host=" . $db_host . ";dbname=" . $db_name . ";charset=utf8mb4", $db_user, $db_pass); } catch (\PDOException $e) { write_log("Cannot connect to DB in user_exists for host::" . $db_host . " || user::" . $db_user . " || pass::" . $db_pass . " || database:: " . $db_name . ". Response: 500 " . $e->getMessage()); return "500 " . $e->getMessage(); $db_conn = null; } } return "200 OK"; } function user_exists($useremail) : string { global $db_conn; $try_connect = db_connect(); if (!function_response($try_connect)==200) { return $try_connect; } $db_qry = $db_conn->prepare("SELECT name, email, login FROM users WHERE email = ?"); $db_qry->execute([$useremail]); $row = $db_qry->fetch(); if (!$row) { return "404 Not Found"; } else { return "200 OK"; } } function user_get_name($useremail) : string { global $db_conn; $try_connect = db_connect(); if (!function_response($try_connect)==200) { return $try_connect; } $db_qry = $db_conn->prepare("SELECT name from users WHERE email = ?"); $db_qry->execute([$useremail]); if ($db_qry->rowCount() > 0) { $retval=""; while ($row=$db_qry->fetch(PDO::FETCH_ASSOC)) { if ($retval=="") { $retval=$row['name']; } else { $retval=$retval . ", " . $row['name']; } } return "200 " . $retval; } else { return "404 Not Found"; } } function user_create($username,$useremail) : string { global $db_conn; $try_connect = db_connect(); if (!function_response($try_connect)==200) { return $try_connect; } try { $db_qry = $db_conn->prepare("INSERT INTO users (name, email, login) VALUES (?, ?, TRUE)"); $db_qry->execute([$username, $useremail]); } catch(Exception $e) { return "403 Forbidden"; } return "200 OK"; } function user_login($useremail) : string { global $db_conn; if (!function_response(user_exists($useremail))==200) { return "404 Not Found"; } if (function_response(user_login_status($useremail))==200) { return "200 OK"; } else { $try_connect = db_connect(); if (!function_response($try_connect)==200) { return $try_connect; } $db_qry = $db_conn->prepare("UPDATE users SET login = TRUE WHERE email = ?"); $db_qry->execute([$useremail]); return "200 OK"; } } function user_login_status($useremail) : string { global $db_conn; $try_connect = db_connect(); if (!function_response($try_connect)==200) { return $try_connect; } if (!function_response(user_exists($useremail))==200) { return "503 Cannot check login status for invalid user"; } $db_qry = $db_conn->prepare("SELECT * FROM users WHERE email = ? AND login = TRUE"); $db_qry->execute([$useremail]); $row = $db_qry->fetch(); if (!$row) { return "401 Unauthorized"; } else { return "200 OK"; } } function write_log($message) { global $file_log; $filehandle = fopen($file_log,"a") or die("Unable to open file!"); fwrite($filehandle, "\n". date("YmdHisvv",time()) . " :: " .$message); fclose($filehandle); } function kill_session() { session_start(); $_SESSION = array(); if (ini_get("session.use_cookies")) { $params = session_get_cookie_params(); setcookie(session_name(), '', time() - 42000, $params["path"], $params["domain"], $params["secure"], $params["httponly"]); } $_SESSION['useremail'] = ''; $_SESSION['FBaccessToken'] = ''; $_SESSION['GGaccessToken'] = ''; session_unset(); session_destroy(); } ?>
- Create the google_redirect.php file:
<?php require_once 'vendor/autoload.php'; include 'config.php'; require_once 'functions.php'; // create Client Request to access Google API $client = new Google_Client(); $client->setClientId($google_clientID); $client->setClientSecret($google_clientSecret); $client->setRedirectUri($google_redirectUri); $client->addScope("email"); $client->addScope("profile"); // authenticate code from Google OAuth Flow if (isset($_GET['code'])) { $token = $client->fetchAccessTokenWithAuthCode($_GET['code']); $client->setAccessToken($token['access_token']); // get profile info $google_oauth = new Google_Service_Oauth2($client); write_log("Submitted Google Authentication Request."); $google_account_info = $google_oauth->userinfo->get(); $email = $google_account_info->email; $name = $google_account_info->name; write_log("Google Authentication Request succeeded with name ". $name . " and email " . $email . "."); // now you can use this profile info to create account in your website and make user logged in. if (function_response(user_exists($email))==404) { write_log("User " . $email . " does not exist. Trying to create..."); //user does not exist, try to create if (!function_response(user_create($name,$email))==200) { write_log("Unable to create user with name " . $name . " and email " . $email . "."); //could not create user, go to error page kill_session(); header("Location: /error.php?error=Cannot%20Create%20User%2E"); exit(); } } //so at this stage either we have a user in the database, or some unknown error occurred if (function_response(user_exists($email))==200) { write_log("User " . $email . " exists. Trying to login..."); //user exists if (function_response(user_login($email))==200) { write_log("User " . $email . " logged in successfully. Creating session and sending to index.php"); //user logged in successfully session_start(); $_SESSION['useremail'] = $email; header("Location: /"); exit(); } else { //user could not be logged in write_log("User " / $email . "could not be logged in. Destroying session and sending to index.php"); kill_session(); header("Location: /"); exit(); } } //if we are here it means some unknown error occurred trying to bind to a user write_log("Cannot bind to user " . $email . ". Sending to error.php"); echo "user_exists: " . user_exists($email) . "<br>"; echo "user_login_status: " . user_login_status($email) . "<br>"; echo "session user: " . $_SESSION['useremail'] . "<br>"; header("Location: /error.php?error=Cannot%20Bind%20To%20User%2E"); exit(); } else { //reached this page without a code, so we need to start the Google Login process write_log("Starting Google Login Process"); echo "<a href='".$client->createAuthUrl()."'>Google Login</a>"; } ?>
- Create the catfile.php file:
<?php include 'config.php'; require_once 'functions.php'; session_start(); if (session_id() == '' || !isset($_SESSION) || $_SESSION['useremail'] == '') { //no session write_log("No session in catfile.php. Sending to error.php"); kill_session(); header("Location: /error.php?error=No%20Active%20Session%2E"); exit(); } if (!function_response(user_exists($_SESSION['useremail'])) == 200) { write_log("Session user " . $_SESSION['useremail'] . "invalid in catfile.php. Destroying session and sending to error.php"); //session user invalid kill_session(); header("Location: /error.php?error=Invalid%20User%20ID%2E"); exit(); } if (!function_response(user_login_status($_SESSION['useremail'])) == 200) { write_log("Session user " . $_SESSION['useremail'] . "not logged-in in catfile.php. Destroying session and sending to error.php"); //session user not logged in kill_session(); header("Location: /error.php?error=User%20Not%20Logged%20In%2E"); exit(); } //if we are here it means we have a valid logged in user write_log("Valid Logged-In User with email: <" . $_SESSION['useremail'] . ">."); write_log("session_id():" . session_id()); write_log("SESSION['useremail']" . $_SESSION['useremail']); $file = $_POST["filename"]; if (!empty($file)) { echo "<h1>This is the content of the file using the file_get_contents instruction</h1><br>"; $filetext=file_get_contents($base_folder . "/library/" . $file); echo $filetext; echo "<br><br><a href=\"/\">Home Page</a>"; } else { $filelist = array_diff(scandir($base_folder . "/library"), array('..','.')); $i=1; echo "<h1>List of available files</h1><br><br>"; echo "<table border=\"1\" style=\"padding:5px\">"; foreach ($filelist as $value) { if ($i==1) echo "<tr>"; echo "<td style=\"padding:5px\">".$value."</td>"; if ($i==5) { echo "</tr>"; $i=0; } $i++; } echo "</table><br><br>"; echo "<form action=\"catfile.php\" method=\"post\">"; echo "Enter desired filename: <input type=\"text\" name=\"filename\"><br>"; // disable button for safety :: echo "<input type=\"submit\">"; echo "</form>"; echo "<br><br><a href=\"/\">Home Page</a>"; } ?>
- Create the logout.php file:
<?php require_once 'functions.php'; kill_session(); header("Location: /"); ?>
- Create the error.php file:
<?php echo '<html><head><meta http-equiv="refresh" content="5;url=/index.php" /></head><body>'; echo '<h1>Error</h1><br><br>'; echo htmlspecialchars($_GET['error']); echo '<br><br>Redirecting...</body></html>'; ?>
Part 3. Scan the Web Application
Now that the application is ready, you can configure your first scan in Acunetix:
- Open Acunetix
- Create a target for your web application
- In the Site Login panel for your target, select Use OAuth for this site
- Set the Grant Type to Authorization Code
- Set the Access token URL to https://www.googleapis.com/oauth2/v4/token
- Set the Authorization URL to https://accounts.google.com/o/oauth2/v2/auth
- Set the Redirect URI to the Google redirect page in your web application; it should match the value of the variable $google_redirectUri in your config.php file
- Set the Client ID to your Google project client ID; it should match the value of the variable $google_clientID in your config.php file
- Set the Client Secret to your Google project client secret; it should match the value of the variable $google_clientSecret in your config.php file
- Set the Scope to profile email; this specifies the resources that will be made available to your web application by Google following authentication
- Click on the Save button
- Click on the 3-Legged Sequence button to allow Acunetix to record a valid login sequence using the Google authentication dialog
- When you have completed the login sequence, the window will close automatically
- Click on the Save button at the top of the page to save your target settings
Your authentication configuration is now ready and you can perform regular Acunetix scans of your target.
Get the latest content on web security
in your inbox each week.