BLOG

Incoherent remblings and other topics of interest

LATEST ENTRIES

Click the post title for a direct link


All the projects I've worked on that rely on pocket_php and make use of POST requests to process user provided data require checking if the request was indeed sent as POST. The HTTPrequest->arguments member variable was supposed to abstract this away by only parsing the POST data into the request arguments array if the request was indeed a POST, if it happened to be a GET request containing data that would otherwise be sent by POST, then the engine would discard those form elements. Not a big deal since it's mandatory to check if the data is even present in the first palce, but the monolithic arguments container still loses the intended context by mashing both GET and POST arguments into a single entity.

The HTTPrequest->arguments variable has been replaced by HTTPRequest->GET & HTTPRequest->POST respectively, this means that all and any inline URL arguments will always be present in GET despite the request having been originally of type POST and the POST argument array will only be populated on POST requests.

Minor change with a big impact in readability.

I still have a beefy backlog to clear but I hope to upload a few pocket_php backed websites as documentation in the coming months.

If you've ever managed any kind of online service you're well aware of how easy it is to abuse unprotected forms. A simple python script can wreak havoc by bombarding a server with randomized input that has to be carefully sanitized to prevent injections. Said processing, however, is typically the most computationally expensive request for a simple website to honor due to the complexity of the steps involved; sanitizing the user input, validating the cleansed data, writing it to a database, etc. Thus, unless we know for certain that the form we received was legitimately answered it is best left discarded, lest we neglect gate-keeping the database only to find it littered with nonsense or worse.

pocket_php captchas samples
The previously mentioned script that fills the form with randomized characters wouldn't be too difficult to detect and mitigate, but a slightly improved version that generates a well formatted email address (regardless of it's authenticity)? Not so much. Even potential solutions, complicated as they mey get, would most likely only work when validating the email field, not the rest of the form which would probably require their own specialized routines. The resulting increase in resource consumption doesn't even ensure the processed form was legit in the first place, only that it passed the aforementioned filters.

For the sake of brevity, now that the problem has been illustrated I'll jump to the point. This is no easy problem to solve, but there are simple and effective precautions that universally apply to internet forms that will at least help deter automated injections, namely captchas.
The idea behind them is quite clever, exploit the fact that there are easy to generate problems that a computer still can't crack but a human can solve in an instant. With character recognition tests being among the more popular.

As for the inevitable cost, captchas may be straightforward but are certainly not free, at least in contrast with leaving a form unprotected, and in cases where the server is working at or near capacity having to generate captchas would definitely worsen the service's responsiveness. On the opposite scenario where the server is practically idling it's quite likely that working the captchas becomes the most expensive step of the form's validation anyway. Alternatively, it's common practice to outsource captchas to reduce the local workload at the expense of the user's privacy.
whichever you choose, safeguarding forms automated attacks has a price, but it is practically ALWAYS WORTH PAYING.

The captcha functionality added to the pocket_php example login page is very simple and effective. It randomizes a set amount of characters from a given input string, draws randomly generated squares to the randomly colored background to obfuscate the foreground, renders the selected characters at a random angle, position and color (within reason, it'd be redundant to make this hard to answer for humans) and finally, the generated string is stored in a PHP session variable to subsequently validate the client's answer. Should the created captcha be too difficult to read for a human, all the client has to do is ask for a new one either by pressing the refresh captcha button or by reloading the form. Ezpz.

Note that the internal login captcha can be (de)activated by setting the ENFORCE_LOGIN_CAPTCHA in app/configure.php and utilizes the php-gd library.

Local, private, effective captcha

Before ending the post I'd like to clarify why captchas were added while other utilities get overlooked from the project. Pocket_php is currently powering fourteen web services with more planned, working with these individual projects I often get tempted to add a particularly handy snippet into the pocket_php codebase for future use, only to scrap the idea in favor of it's original vision; to provide the fastest, simplest template for webprojects to use as foundation. Abiding by this rule means that certain kinds of utilities are often not incorporated into source due to them being either too situational or just not worth the effort to implement on behalf of the programmer.

What separates captchas from other potential features is how necessary they've become and how widespread the use of (often subversive) third-party captcha services has grown in response, specially among sites that don't really benefit from such an approach at all. In the end, it's not about how easy or fast it is implement captchas, it's about having the option of privacy at the same reach as the alternatives.

Pocket_php's session manager has been updated to handle both inactivity timeouts and login expiration independently from the php-fpm daemon configuration, this enables projects with different session configurations to be simultaneously run on the same web server. The demo website was also updated. Updating to 1.3.

The new pocket_php demo site

PHP's native cookie management is already as simple as it can possibly be, wrapping its minimalism around a mere rebranded interface would only bloat the codebase. Though I have yet to encounter the need to modify said cookies policy, the encapsulation of the cookies themselves and off the PHP global scope fits the overall design better, the HTTPRequest class now has a container for all of the client's cookies.

Updated to 1.2.

In Pocket_PHP ver1.0 the included configuration file for the NGINX virtual server block allowed all non .php files within the specified root directory to be publicly available. This was intentionally done to keep the rules as general and open as possible, should the need arise to limit access to certain file names and formats it could be filtered either through NGINX or in some cases (like hidden UNIX files) through Pocket_PHP.

This meant that the internal sqlite database file (/app/core/pocket_php.db) was available for download as a static file, with the new VBS rules such files can be blocked by the webserver itself. As an alternative to keep such files publicly available by the webserver while simultaneously keeping files of the same format as private, place said files outside the root (/app/) folder and thus inaccesible to the NGINX process. Just make sure to give the php-fpm daemon access to this private folder.

Lastly, the www. extention is by now irrelevant, an extra server block was added to the configuration file to redirect calls with the www. prefix to be redirected to the clean URL.

Here's the updated VBS config for NGINX 1.17:

server {

    listen 80;
    listen [::]:80;
    listen 443;
    listen [::]:443;

    server_name www.pocket_php.localhost.localhost;
    return 301 $scheme://pocket_php.localhost$request_uri;
}


server {
   listen 80 default_server;
   listen [::]:80 default_server;

    listen 443 ssl http2 default_server;
    listen [::]:443 ssl http2 default_server;

    # Change to your own certs
    ssl_certificate     /etc/nginx/ssl/pocket_php.crt;
    ssl_certificate_key /etc/nginx/ssl/pocket_php.key;
    ssl_ciphers         EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH;
    # ssl_dhparam         /root/certs/example.com/dhparam4096.pem;
    ssl_prefer_server_ciphers on;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    ssl_session_cache   shared:SSL:10m;
    ssl_session_timeout 10m;

    # Whatever folder you pick, it must be owned by the same user:group running the 
    # nginx instance, permissions should be 775 for maximum security gainz
    root /var/www/html/pocket_php/app/;
    
    # Add index.php to the list if you are using PHP
    index index.php;

    # LOCAL SERVER NAME (remember to add the localhost address to /etc/hosts)
    server_name pocket_php.localhost www.pocket_php.localhost;

    # Do not serve hidden files (.filename)
    location ~ /\. {
        deny all;
    }

    # Serve static files directly
    location ~* ^.+.(jpg|jpeg|gif|css|png|js|ico|webm|txt|asc)$ {
         access_log off;
         expires    30d;
         try_files $uri =404;
         #deny all;
    }   

    # Deny sqlite.db files
    location ~* ^.+.(db)$ {
         deny all;
    }

    # Execute all .php files
    location ~ \.php$ {
         include fastcgi.conf;
         fastcgi_pass unix:/run/php-fpm/php-fpm.sock;
         fastcgi_param SCRIPT_FILENAME /var/www/html/pocket_php/app/index.php;   
    }

    # Redirect all requests to /app/index.php
    location / {
         #try_files $uri $uri/ /index.php?$args;
         try_files $uri /index.php?$args;
    }

    # Redirect errors to pocket_php
    fastcgi_intercept_errors on;
    error_page 400 403 404 /index.php;
}

A friend of mine let me know that xenspace.net wasn't available through certian browsers (like Safari) that discard all "non secure" sites by default. Turns out I forgot to update the site's SSL certificate.
I requested a new one and in the process of verifiying ownership of the site, I realized that pocket_php (the server's backend) didn't support access to folders that began with a ".". I updated the configuration.php file, adding two constants that represent the assigned strings as well as new routing exceptions for the very specific URL the certificate authority uses to validate the site.

Note that this requires a simple server configuration update, see the provided "default" nginx configuration file.

While setting up a client's VPS to host a pocket_php based web project I noticed the include nginx.conf file is no longer compatible with nginx ver. 1.16.1. The "group" directive has been deprecated and must now be specified in after the user in the "user" variable field.

I rather keep all relevant info related to the project's development here. PHP is still seen as a "funny" tool of the past, like those bone saws that surgeons used to amputate limbs. It seems to me that those that ironically hold these opinions are just inexperienced for they have yet to understand that Web development is shit by nature, regardless of the tools used.

I can't remember when I originally started working on pocket_php, since the original devlog is mostly useless I'll just start fresh here.