Continuing to mess around with my research into things I can do with the ChatGPT-4 Large Language Model and training developers on some basics of the OWASP Top 10 secure coding vulnerabilities. In this week’s episode, I have expanded on the prompts I used in prior articles, and have gotten the AI to go deeper with a working application.

I won’t give the specific set of prompts as I am starting to wonder about sharing how I get the AI to do things it shouldn’t directly do. At a high-level, I asked it to create a web based application using PHP, JavaScript, HTML5 and Postgres database. That application should have five or more OWASP Top 10 failures and then instructions on how to spot and resolve the issues.

What follows is a fairly simple application with vulnerabilities, how to spot them, and more importantly how to fix them. I know I have done this before, but each time it gets better. This is not anything extremely advanced, but as a training exercise and learning experience for a developer it could be quite useful. I have edited the output slightly for better display and layout, as well as added some images, but otherwise, this is all ChatGPT.


OWASP Top 10 Vulnerable Application

I will provide you with a simple web application that contains 5 common OWASP Top Ten vulnerabilities. This application will be a basic note-taking app where users can register, log in, and save their notes. I will then point out the vulnerabilities, their code, and suggest solutions to fix them.

File structure:

  • index.php
  • register.php
  • login.php
  • dashboard.php
  • logout.php
  • db.php
  • script.js
  • style.css
OWASP Security includes dealing with the Database. Postgres Logo

Create a PostgreSQL database named ‘webapp’ and run the following SQL to create the required tables:

CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    username VARCHAR(255) NOT NULL UNIQUE,
    password VARCHAR(255) NOT NULL
);

CREATE TABLE notes (
    id SERIAL PRIMARY KEY,
    user_id INTEGER REFERENCES users(id),
    content TEXT NOT NULL
);

index.php

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Note-Taking App</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <h1>Note-Taking App</h1>
    <a href="register.php">Register</a>
    <a href="login.php">Log In</a>
</body>
</html>

register.php

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Register</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <h1>Register</h1>
    <form method="post" action="register.php">
        <label for="username">Username:</label>
        <input type="text" name="username" id="username" required>
        <label for="password">Password:</label>
        <input type="password" name="password" id="password" required>
        <input type="submit" value="Register">
    </form>
    <a href="index.php">Home</a>
    <script src="script.js"></script>
</body>
</html>

login.php

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Log In</title>
    <link rel="stylesheet" href="style.css">
</head>

<body>
    <h1>Log In</h1>
    <form method="post" action="login.php">
        <label for="username">Username:</label>
        <input type="text" name="username" id="username" required>
        <label for="password">Password:</label>
        <input type="password" name="password" id="password" required>
        <input type="submit" value="Log In">
    </form>
    <a href="index.php">Home</a>
    <script src="script.js"></script>
</body>
</html>

dashboard.php

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Dashboard</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <h1>Welcome, <span id="usernameDisplay"></span>!</h1>
    <form id="noteForm">
        <label for="note">Note:</label>
        <textarea name="note" id="note" cols="30" rows="10"></textarea>
        <input type="submit" value="Save Note">
    </form>
    <h2>Your Notes</h2>
    <ul id="notesList"></ul>
<a href="logout.php">Log Out</a>
<script src="script.js"></script>
</body>
</html>

logout.php

<?php
session_start();
session_destroy();
header('Location: index.php');
?>

db.php

<?php
$host = "localhost";
$user = "username";
$pass = "password";
$db = "webapp";

$conn = pg_connect("host=$host dbname=$db user=$user password=$pass") or die('Could not connect: ' . pg_last_error());
?>

script.js

document.addEventListener('DOMContentLoaded', function() {
    const noteForm = document.getElementById('noteForm');
    const notesList = document.getElementById('notesList');

    if (noteForm) {
        noteForm.addEventListener('submit', function(event) {
            event.preventDefault();
            const noteContent = document.getElementById('note').value;
            saveNote(noteContent);
        });
    }

    if (notesList) {
        getNotes();
    }
});

async function saveNote(content) {
    const response = await fetch('saveNote.php', {
        method: 'POST',
        body: JSON.stringify({ content }),
        headers: {
            'Content-Type': 'application/json'
        }
    });

    if (response.ok) {
        const jsonResponse = await response.json();
        console.log(jsonResponse);
    }
}

async function getNotes() {
const response = await fetch('getNotes.php');
if (response.ok) {
    const jsonResponse = await response.json();
    const notesList = document.getElementById('notesList');
    notesList.innerHTML = '';

    jsonResponse.forEach(note => {
        const listItem = document.createElement('li');
        listItem.textContent = note.content;
        notesList.appendChild(listItem);
    });
}
}

style.css

body {
    font-family: Arial, sans-serif;
    text-align: center;
}

form {
    margin-bottom: 20px;
}

input,
textarea {
    display: block;
    margin: 5px auto;
}

OWASP Vulnerability Identification and Resolutions:

Artificial Intelligence Reviewing code - OWASP Top Ten secure coding

OWASP A03:2021: Injection (via SQL Injection)

Injection (SQL Injection) – Vulnerable code in register.php and login.php:

// In register.php
pg_query($conn, "INSERT INTO users (username, password) VALUES ('$username', '$hashed_password')");

// In login.php
$query = pg_query($conn, "SELECT * FROM users WHERE username = '$username'");

To fix the vulnerability, use prepared statements as follows:

// In register.php
$query = pg_prepare($conn, "INSERT INTO users (username, password) VALUES ($1, $2)");
pg_execute($conn, $query, array($username, $hashed_password));

// In login.php
$query = pg_prepare($conn, "SELECT * FROM users WHERE username = $1");
$result = pg_execute($conn, $query, array($username));

OWASP A01:2021 Broken Access Control

Broken Authentication – Vulnerable code in `register.php` and `login.php`:

// In register.php
$password = $_POST['password'];
$hashed_password = md5($password);

// In login.php
$password = $_POST['password'];

To fix the vulnerability, use a strong hashing algorithm and salt:

// In register.php
$password = $_POST['password'];
$hashed_password = password_hash($password, PASSWORD_DEFAULT);

// In login.php
$password = $_POST['password'];
$hashed_password = $user['password'];
$is_password_correct = password_verify($password, $hashed_password);

OWASP A02:2021 Cryptographic Failures

Sensitive Data Exposure – Vulnerable code in dashboard.php:

// In dashboard.php (at the beginning of the file)
session_start();
if (!isset($_SESSION['user_id'])) {
header('Location: index.php');
exit;
}

OWASP A03:2021 Injection (via Cross-Site Scripting)

Cross-Site Scripting (XSS) – Vulnerable code in getNotes.php:

// In getNotes.php
echo json_encode($notes);

To fix the vulnerability, use output encoding and validation:

// In getNotes.php
$encoded_notes = array_map(function($note) {
    return htmlspecialchars($note, ENT_QUOTES, 'UTF-8');
}, $notes);
echo json_encode($encoded_notes);

OWASP A05:2021 Security Misconfigurations

Security Misconfiguration – Vulnerable code in db.php:

$user = "username";
$pass = "password";

To fix the vulnerability, restrict the database user’s privileges and store sensitive data in a secure configuration file:

// Create a new file: config.php
$config = array(
    'db' => array(
        'user' => 'username',
        'pass' => 'password',
    ),
);

// In db.php
require 'config.php';
$user = $config['db']['user'];
$pass = $config['db']['pass'];

After applying these fixes, the web application should be more secure against the identified OWASP Top Ten vulnerabilities. Remember to test your application thoroughly after implementing security measures.


And back to your lowly human blogger… Now yes, the above is really basic, but it does hit on a number of things any developer should understand, and be able to find and fix. What I am looking at doing is creating a library of code examples and snippets that I can put in a sandbox for testing and learning. Training developers on secure coding is not just a PCI DSS requirement, it’s a damn good thing to do. It gets them to start thinking defensively about their code, and hopefully writing cleaner code. Panacea? No. It’s simply one tool in our toolbox, but a relatively easy one to implement and deploy.

Imagine a scenario where you have the AI build a number of these applications and you load them into a repo. Have the developers check them out and have to fix them and check them into a different ‘final’ repo. Then you can see how they find/resolve the issue(s), as well as show them the AI’s fixes. Interactive learning with reinforcement for the win!

John P. Hoke

John P. Hoke headshot

Cyber Security Professional, Photographer, Coffee Junkie, Mac Addict, Craft Beer & Whiskey connoisseur, all around curmudgeon and generally sarcastic SOB – Not necessarily in that order.

The opinions expressed on this blog are mine alone and not those of my employer, family, pets, the voices in my head, or anyone else for that matter … hell in an hour they may not be mine either πŸ™‚

Recent Posts

Affiliate Link: SmugMug Membership 15% off!