I have a simple robot I am working on. There is a webpage, using arrows to navigate, and a streaming webcam. I've been reading that using exec(command) is insecure. Unfortunately, I don't know how to get user input from the webpage, to securely execute code on the Raspberry Pi.

For now, I have included a few checks for date, time, user, (max run time) duration, start time, etc.

But, I would rather know how to securely get user control input from a web page, to control the I/O pins of the Raspberry Pi.

Here's a fragment: It's from the old interface, but I am still using the same basic methodology to process instructions.

    if (isset($_POST['Submit1']))
        $reg_wvar      = isset($_POST['nmr']);
        $reg_UName     = $_POST['UName'];
        $reg_Date      = $_POST['ddate'];
        $reg_startTime = $_POST['startTime'];
        $reg_ToD       = $_POST['ToD'];
        $reg_duration  = $_POST['duration'];

        $r = "$reg_Date $reg_startTime $reg_ToD, $reg_duration, $reg_UName \n";
        //echo $r . $reg_wvar;

        $selected_radio = $_POST['nmr'];
            case $reg_wvar = "left":
                $du = 'left.py';
                $command = "$du $r";
                echo exec($command);

            case $reg_wvar = "right":
                $du = 'right.py';
                $command = "$du $r";
                echo exec($command);


1 Answer 1


exec() is potentially insecure, because it can execute any command on your system that the PHP process has permission to run. The key to using it securely is to ensure that the command you send to exec() never contains direct user input.

Your example code is insecure because $command depends on unfiltered user input from $_POST via $r. Although $r is only supposed to set the parameters for the command, it can still be constructed in such a way that it calls other commands. You cannot depend on the web interface to set only valid data in the $_POST fields, because it is very easy for a hacker to build an HTTP request with any data they like.

Ideally, the way around this is to do checks on the user input then set $command using only data that is generated by your script (is it one of a pre-set list of strings, or a number in a certain range?). You have done this correctly for setting $du - the insecure example would be setting $du = $reg_wvar . '.py'.

Sometimes you do have to pass user input, such as your username parameter. In this case, you have to make sure that anything nasty is filtered out of the input before you use it in a command. This answer will be helpful.

The other thing to consider is what happens when the command is executed. The Raspberry Pi GPIO pins normally need root permissions for access, but it's a bad idea to give PHP (or your Python scripts) that level of permission. To address this, you need to set up the GPIO beforehand, and set permissions that allow them to be used by your Python scripts without needing sudo.

I use the script below to set up GPIO on my system when it boots. It's called from the /etc/rc.local file, so it runs once at startup with root permissions:

if ! [[ -e /sys/class/gpio/gpio27 ]]; then
        echo "27" > /sys/class/gpio/export
echo "out" > /sys/class/gpio/gpio27/direction
echo "0"   > /sys/class/gpio/gpio27/value
chmod 664    /sys/class/gpio/gpio27/value
chgrp gpio   /sys/class/gpio/gpio27/value

This configures pin 27 as an output, then sets the permissions so that it can be written to by members of the gpio group. I set up this group to include the username of my web server.

If you need more flexibility (e.g. reconfiguring the GPIO pins from your Python scripts), then look at the wiringPi GPIO Utility. It is a little less secure because it uses root permissions when it runs, but the risk is a lot lower than running your own scripts as root.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.