Search code examples
phpxmlauthenticationsimplexml

XML Database Array doing weird things. Trying to authenticate login using XML and PHP


The Objective

To fetch the data from the XML "database" as a simple (and I know, very insecure) way of verifying login data.

The code here is that responsible for the database and for retrieving the values. Option one is what I originally tried, so it still contains the code which cross-references the input data of the username and password with the data in the XML database. Option two is where I tried a different method. Neither seem to be working. Screenshots attached.

Option One:

login.php:

<?php
if( !isset($_SESSION['user']) ) { ?>
<div>Please login to view your message log, and see whether anyone has left you a message.</div>
<form action="php/authenticate.php" method="POST" >
    <input type="text" name="Username" />
    <input type="password" name="Password" />
    <input type="submit" value="Login" />
</form>
<?php };
$passwordValid = $_GET['error'];
if( $passwordValid == 1 ) {
    echo "Falsches Password";
};
?>

authenticate.php:

<?php
session_start();

    // Load Credential Database
    $xml = new DOMDocument();
    $xml->load('../logins.xml');
    $xpath = new DOMXPath($xml);

    // Variable Declarations
    $user = $_POST['Username'];
    $password = $_POST['Password'];

    // XPath Query for Correct Credential
    $queryUsers = '//authentication/client/user[. = "' . $user . '"]';
    $userActual1 = $xpath->query($queryUsers);
    $userActual = $userActual1->nodeValue; // Output: Anton
    $passwordActual1 = $userActual1 . 'following-sibling::*[1]';
    $passwordActual = $xpath->query($passwordActual1); // Output: damn

    // Authentication Checker
    if($user == 'Arend' && $password == 'damn') {
        $userLogin = true;
        $_SESSION['user'] = $user;
        header('Location: ../index.php');
    } else {
        $userLogin = false;
        header('Location: ../index.php?error=1');

    };

    if($userLogin == true) {
        header('Location: ../index.php');
    };
?>

XML "logins.xml":

<?xml version="1.0" encoding="UTF-8"?>
<authentication>
    <client>
        <user>Arend</user>
        <password>damn</password>
    </client>
    <client>
        <user>Felipe</user>
        <password>damned</password>
    </client>
    <client>
        <user>Paula</user>
        <password>damnest</password>
    </client>
</authentication>

Option Two:

XML code "test.xml":

<?xml version="1.0" encoding="UTF-8"?>
<authentication>
    <user name="Arend">
    </user>
        <password>damn</password>
    <user name="Paula">
    </user>
        <password>damnest</password>
</authentication>

php code:

<?php
    $xml = simplexml_load_file('test.xml');
    $nodes = $xml->xpath('//authentication/user[@name="Arend"]');

    // Variable Declarations
    $user = "Arend";
    $password = "damn";

    echo 'second test' . '<br>';
    print_r ($nodes);
    echo '<br>';
    print_r ($nodes[0]['name']);
    echo '<br>';
    echo $nodes[0]['name'];
?>

Result:

As you can see, it grabs the XML data and the array and how it is structured cen be viewed in the screenshot. I am able to get the username, but if I try to specify the password (echo $nodes[0]['password'];) as the thing I want, it comes up with the second image below:


Solution

  • You acknowledge that this is insecure, so I won't badger or comment anymore on that.

    As for using logins.xml, as in your first example, I had a proper XPath and solution for it. I used simpleXML though, which comes with PHP.

    //load credentials
    $xml = simplexml_load_file(__DIR__.'/logins.xml');
    // Variable Declarations
    $user = $_POST['Username'];
    $password = $_POST['Password'];
    $search = $xml->xpath("//authentication/client[./user = '{$user}'][./password = '{$password}']");
    
    if(count($search))
    {
        //authenticated!
    }
    else
    {
        //DENIED
    }
    

    It does a match of a <client> node having BOTH a child <user> equal to $user and a <password> equal to $password, not either-or, but both.

    count($search) returns 0 (false) if there are none, and then anything else is cast to true, which means they exist in your dataset.

    • Disclaimer, I used __DIR__ because the XML and PHP were in the same folder for me when I tested my XPath expression. I want to say NEVER have your sensitive credentials within the web root, or somewhere not protected by some form of HTAccess or other restriction.

    For using DOMDocument and DOMXPath, they have instead of a countable set a length parameter. You instead would have this for checking IF/ELSE

    $xmlpath= $xpath->query("//authentication/client[./user = '{$user}'][./password = '{$password}']");
    if($xmlpath->length > 0)
    {
        //authenticate
    }
    else
    {
        //not
    }
    

    One final security warning, you use direct $_POST variables, and I want to add awareness that there is such a thing as XPath Injection, much like SQL injection. Your function isn't used to display data, so it wouldn't be leaking information from the document. BUT they could use it to make a query that always returns true and lets them log in.

    See for examples, including login credentials in XML like yours!: https://www.owasp.org/index.php/XPATH_Injection