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:

  1. Go to the Google Cloud Platform dashboard
  2. Click on the Create project button

      

  3. Set the project name (here: AX-example) and click on the Create button

      

  4. Go to APIs & Services → OAuth consent screen

      

  5. Set the User Type to External and click on the Create button to proceed to the OAuth consent screen

      

  6. 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

      

  7. 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

      

  8. 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

      

  9. In the Scopes screen, click on the Add or remove scopes button

      

  10. In the Update selected scopes popup, select the scopes your application requires; typically you would start with the email, the profile, and the openid
  11. Scroll to the bottom of the popup and click on the Update button to confirm your selected scopes

      

  12. Next, scroll to the bottom of the Scopes page and click on the Save and continue button to proceed to the Test users page
  13. 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

      

  14. 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

      

  15. Next, go to the Google Search Console
  16. In the URL prefix panel, enter the URL prefix for your domain and click on the Continue button

      

  17. 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
  18. Click on the filename to download the file, upload it to the root of your website, and click on the Verify button

      

  19. Click on the Done button to end the Domain Verification process

      

  20. Back on the APIs & Services page in the Google Cloud Platform, click on the Domain verification menu option

      

  21. Click on the Add domain button

      

  22. Enter your domain name and click on the Add domain button

      

  23. Your Domain verification page will now show your domain in the Allowed domains list

      

  24. Back on the APIs & Services page in the Google Cloud Platform, click on the Credentials menu option

      

  25. Click on the Create credentials button and select OAuth client ID from the dropdown
  26. 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

      

  27. 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

  1. 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>
    
  2. 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
  3. 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();
    }
    ?>
    
  4. 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>";
    }
    ?>
    
  5. 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>";
    }
    ?>
    
  6. Create the logout.php file:
    <?php
    require_once 'functions.php';
    kill_session();
    header("Location: /");
    ?>
    
  7. 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:

  1. Open Acunetix
  2. Create a target for your web application
  3. In the Site Login panel for your target, select Use OAuth for this site

      

  4. Set the Grant Type to Authorization Code
  5. Set the Access token URL to https://www.googleapis.com/oauth2/v4/token
  6. Set the Authorization URL to https://accounts.google.com/o/oauth2/v2/auth
  7. 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
  8. 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
  9. 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
  10. Set the Scope to profile email; this specifies the resources that will be made available to your web application by Google following authentication
  11. Click on the Save button
  12. Click on the 3-Legged Sequence button to allow Acunetix to record a valid login sequence using the Google authentication dialog

      

  13. When you have completed the login sequence, the window will close automatically
  14. 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.

SHARE THIS POST
THE AUTHOR
Kevin Attard Compagno
Technical Writer
Kevin Attard Compagno is a Technical Writer working for Acunetix. A technical writer, translator, and general IT buff for over 30 years, Kevin used to run Technical Support teams and create training documents and other material for in-house technical staff.