Laravel - Executing client side exe file via Plesk Server

139 Views Asked by At

Essentially, I would like to run a shell command from a Laravel app to my local client PC. The objective is to execute an exe file on my local Windows 7 machine located in the C drive. This functionality works when running Laravel in localhost, but it doesn't work after deploying it to a Plesk server.

Any suggestions?

Thanks.

Update: I understand that this can be done using ssh2 but it seems like quite risky in terms of security. So looking for alternative way.

My current code:

$exePath = 'C:\\ProgramData\\ADWinCT\\RsKey.exe';

$scriptPath = 'C:\\ProgramData\\ADWinCT\\script.exe';

$commandRsKey = "start /B \"\" \"$exePath\"";

exec($commandRsKey);


$commandScript = "start /B cmd /c \"$scriptPath\"";

exec($commandScript);
1

There are 1 best solutions below

0
VonC On BEST ANSWER

Direct execution of local executables through server-side code (like PHP in Laravel) is not feasible for remote clients due to security restrictions in browsers and operating systems. However, there are alternative approaches to achieve a similar outcome, focusing on client-side solutions and secure remote execution methods.

Your current approach works locally because the PHP exec function executes a command on the server's operating system. When deployed to a Plesk server, the command attempts to run on the server itself, not the client machine. For remote execution, technologies like SSH or PowerShell remoting could be considered but are outside the web application's typical use case and, as you noted, come with significant security implications.

As noted in the comments, executing an .exe file on a client's machine through a web application also poses significant security risks. But the functionality you require (interfacing with a weight scale machine) means a local solution due to the direct hardware interaction involved (assuming an application stored in a secure, predefined location).

Executing client-side executables from a server-side Laravel application requires a shift in approach, focusing on client-side technologies or secure, authenticated desktop applications that interact with your server.


So a more viable approach would be to trigger the execution from the client side using technologies that the client has control over.
Develop a lightweight desktop application that listens for specific commands from your Laravel application (e.g., via websockets or polling an API endpoint) and then executes the local .exe files. That application would need to be installed on the client's machine.

To invoke the WebSocket in the desktop application from a Laravel application, you would typically send messages to a WebSocket server that the desktop application is connected to.
The Laravel app would not directly communicate with the desktop application; instead, it would communicate via a WebSocket server that relays messages between the Laravel app and the desktop app.

+------------------+         +---------------------+         +-------------------+         +-----------------------+
|                  |         |                     |         |                   |         |                       |
|  Laravel App     |         |  WebSocket Server   |         |  Desktop App      |         |  Local Executable     |
|                  |         |                     |         |                   |         |  (e.g., RsKey.exe)    |
+-------+----------+         +---------+-----------+         +--------+----------+         +-----------+-----------+
        |                              |                              |                                  |
        | 1. Send command/message      |                              |                                  |
        |------------------------------->                             |                                  |
        |                              |                              |                                  |
        |                              | 2. Forward command/message   |                                  |
        |                              |------------------------------>                                  |
        |                              |                              |                                  |
        |                              |                              | 3. Execute local executable      |
        |                              |                              |--------------------------------->|
        |                              |                              |                                  |
        |                              |                              | 4. Executable performs action    |
  • The Laravel application sends a command or message to the WebSocket server. That command could be anything that you have predefined to trigger the execution of a local executable on the desktop application side (e.g., {"action": "runExecutable", "path": "C:\\ProgramData\\ADWinCT\\RsKey.exe"}).
  • The WebSocket server receives this command/message and forwards it to the connected desktop application. The desktop application is constantly listening for messages from the WebSocket server.
  • Upon receiving the specific command/message, the desktop application then executes the local executable file specified in the command. That step involves the desktop application running a command like Process.Start(@"C:\ProgramData\ADWinCT\RsKey.exe") in its code.
  • The local executable (RsKey.exe in this example) is then run on the desktop, performing whatever action it is designed to do, in your case, interfacing with a weight scale machine.

Regarding Websocket, Node.js with the ws library (or any other WebSocket server implementation you want) is a possible option.
In your Laravel application, you can use a PHP WebSocket client to send messages to the WebSocket server, for instance sirn-se/websocket-php, which replaces the old textalk/websocket.

<?php

namespace App\Services;

use WebSocket\Client as WebSocketClient;
use WebSocket\Connection;
use WebSocket\Message\Message;
use WebSocket\Middleware\PingResponder;
use WebSocket\Middleware\CloseHandler;

class WebSocketService
{
    protected $client;

    public function __construct($url)
    {
        $this->client = new WebSocketClient($url);
        $this->client->addMiddleware(new CloseHandler())
                     ->addMiddleware(new PingResponder());
    }

    public function sendMessage($message)
    {
        // Send a message
        $this->client->text($message);

        // Optionally, read the response if necessary
        $response = $this->client->receive();
        echo "Got response: {$response->getContent()} \n";

        // Close the connection
        $this->client->close();
    }
}

You can use this service in your Laravel controller to send messages through the WebSocket:

<?php

namespace App\Http\Controllers;

use App\Services\WebSocketService;
use Illuminate\Http\Request;

class WebSocketController extends Controller
{
    public function triggerAction(Request $request)
    {
        $message = "Your custom message here"; // Customize your message

        $webSocketUrl = "wss://yourwebsocketserver.com"; // Your WebSocket server URL
        $webSocketService = new WebSocketService($webSocketUrl);
        
        try {
            $webSocketService->sendMessage($message);
            return response()->json(['success' => true, 'message' => 'Message sent successfully']);
        } catch (\Exception $e) {
            return response()->json(['success' => false, 'error' => $e->getMessage()]);
        }
    }
}

Make sure to create a route for your controller method if you have not already:

Route::post('/trigger-action', [WebSocketController::class, 'triggerAction']);

That will allow your Laravel application to communicate with a WebSocket server, which in turn can communicate with any listening clients, such as your desktop application.

You would need to implement authentication for both the Laravel app and the desktop application when they connect to the WebSocket server. That would make sure only authorized applications can send and receive messages. And sanitize incoming messages to avoid executing unintended commands. Use wss:// (WebSocket Secure) for your WebSocket connections to make sure the data transferred is encrypted.


The desktop application would also need to be securely authenticated to your server, and you should make sure all communication is encrypted (again, using WSS for websockets).
As a simplified example (in pseudocode):

// C# .NET Core Console Application (Pseudocode)
using System;
using System.Diagnostics;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        var client = new ClientWebSocket();
        await client.ConnectAsync(new Uri("wss://yourserver.com/socket"), CancellationToken.None);

        while (client.State == WebSocketState.Open)
        {
            ArraySegment<byte> bytesReceived = new ArraySegment<byte>(new byte[1024]);
            WebSocketReceiveResult result = await client.ReceiveAsync(bytesReceived, CancellationToken.None);
            
            // Assume the message is a command to run the executable
            string message = System.Text.Encoding.UTF8.GetString(bytesReceived.Array, 0, result.Count);
            if (message.Contains("run_exe"))
            {
                Process.Start(@"C:\ProgramData\ADWinCT\RsKey.exe");
                // Similarly handle other commands
            }
        }
    }
}

That would be the basic structure for a console application that listens for commands over a WebSocket connection and executes a local executable file when a specific command is received: it enables a remote server (via secure web sockets) to request the execution of a local executable file indirectly by sending commands to the application running on the client machine.
(Plus, you would need error handling, security features, and more robust command parsing for production use).