Skip to content

Commit

Permalink
Merge pull request #97 from AikidoSec/support-laravel-env
Browse files Browse the repository at this point in the history
Extensive Forge & Laravel support
  • Loading branch information
willem-delbare authored Dec 5, 2024
2 parents 93b2eab + 8670d20 commit 8920e07
Show file tree
Hide file tree
Showing 24 changed files with 126 additions and 34 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ Prerequisites:

#### For Red Hat-based Systems (RHEL, CentOS, Fedora)

`rpm -Uvh --oldpackage https://github.com/AikidoSec/firewall-php/releases/download/v1.0.98/aikido-php-firewall.x86_64.rpm`
`rpm -Uvh --oldpackage https://github.com/AikidoSec/firewall-php/releases/download/v1.0.99/aikido-php-firewall.x86_64.rpm`

#### For Debian-based Systems (Debian, Ubuntu)

```
curl -L -O https://github.com/AikidoSec/firewall-php/releases/download/v1.0.98/aikido-php-firewall.x86_64.deb
curl -L -O https://github.com/AikidoSec/firewall-php/releases/download/v1.0.99/aikido-php-firewall.x86_64.deb
dpkg -i ./aikido-php-firewall.x86_64.deb
```

Expand All @@ -52,7 +52,7 @@ Create a new file in `.ebextensions/01_aikido_php_firewall.config` with the foll
```
commands:
aikido-php-firewall:
command: "rpm -Uvh --oldpackage https://github.com/AikidoSec/firewall-php/releases/download/v1.0.98/aikido-php-firewall.x86_64.rpm"
command: "rpm -Uvh --oldpackage https://github.com/AikidoSec/firewall-php/releases/download/v1.0.99/aikido-php-firewall.x86_64.rpm"
ignoreErrors: true
files:
Expand Down
2 changes: 1 addition & 1 deletion lib/agent/aikido_types/init_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ type AikidoConfigData struct {
LogLevel string `json:"log_level,omitempty"` // default: 'INFO'
Blocking bool `json:"blocking,omitempty"` // default: false
LocalhostAllowedByDefault bool `json:"localhost_allowed_by_default,omitempty"` // default: true
CollectApiSchema bool `json:"collect_api_schema,omitempty"` // default: false
CollectApiSchema bool `json:"collect_api_schema,omitempty"` // default: true
}

type RateLimiting struct {
Expand Down
2 changes: 1 addition & 1 deletion lib/agent/globals/constants.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package globals

const (
Version = "1.0.98"
Version = "1.0.99"
ConfigUpdatedAtMethod = "GET"
ConfigUpdatedAtAPI = "/config"
ConfigAPIMethod = "GET"
Expand Down
2 changes: 1 addition & 1 deletion lib/agent/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ toolchain go1.23.3

require (
github.com/stretchr/testify v1.9.0
google.golang.org/grpc v1.68.0
google.golang.org/grpc v1.68.1
google.golang.org/protobuf v1.34.2
)

Expand Down
2 changes: 2 additions & 0 deletions lib/agent/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E=
google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0=
google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA=
google.golang.org/grpc v1.68.1 h1:oI5oTa11+ng8r8XMMN7jAOmWfPZWbYpCFaMUTACxkM0=
google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe00waw=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
Expand Down
20 changes: 20 additions & 0 deletions lib/agent/grpc/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"main/log"
"net"
"os"
"path/filepath"

"google.golang.org/grpc"
"google.golang.org/protobuf/types/known/emptypb"
Expand Down Expand Up @@ -80,18 +81,37 @@ func StartServer(lis net.Listener) {
lis.Close()
}

// Creates the /run/aikido-* folder if it does not exist, in order for the socket creation to succeed
// For now, this folder has 777 permissions as we don't know under which user the php requests will run under (apache, nginx, www-data, forge, ...)
func createRunDirFolderIfNotExists() {
runDirectory := filepath.Dir(globals.EnvironmentConfig.SocketPath)
if _, err := os.Stat(runDirectory); os.IsNotExist(err) {
err := os.MkdirAll(runDirectory, 0777)
if err != nil {
log.Errorf("Error in creating run directory: %v\n", err)
} else {
log.Infof("Run directory %s created successfully.\n", runDirectory)
}
} else {
log.Infof("Run directory %s already exists.\n", runDirectory)
}
}

func Init() bool {
// Remove the socket file if it already exists
if _, err := os.Stat(globals.EnvironmentConfig.SocketPath); err == nil {
os.RemoveAll(globals.EnvironmentConfig.SocketPath)
}

createRunDirFolderIfNotExists()

lis, err := net.Listen("unix", globals.EnvironmentConfig.SocketPath)
if err != nil {
panic(fmt.Sprintf("failed to listen: %v", err))
}

// Change the permissions of the socket to make it accessible by non-root users
// For now, this socket has 777 permissions as we don't know under which user the php requests will run under (apache, nginx, www-data, forge, ...)
if err := os.Chmod(globals.EnvironmentConfig.SocketPath, 0777); err != nil {
panic(fmt.Sprintf("failed to change permissions of Unix socket: %v", err))
}
Expand Down
5 changes: 0 additions & 5 deletions lib/php-extension/Aikido.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,6 @@ PHP_MSHUTDOWN_FUNCTION(aikido) {

PHP_RINIT_FUNCTION(aikido) {
AIKIDO_LOG_DEBUG("RINIT started!\n");

if (!AIKIDO_GLOBAL(environment_loaded)) {
LoadEnvironment();
AIKIDO_GLOBAL(environment_loaded) = true;
}

if (AIKIDO_GLOBAL(disable) == true) {
AIKIDO_LOG_INFO("RINIT finished earlier because AIKIDO_DISABLE is set to 1!\n");
Expand Down
27 changes: 24 additions & 3 deletions lib/php-extension/Environment.cpp
Original file line number Diff line number Diff line change
@@ -1,22 +1,43 @@
#include "Includes.h"

std::string GetEnvVariable(const std::string& env_key) {
std::string GetLaravelEnvVariable(const std::string& env_key) {
zval env_value;
if (!CallPhpFunctionWithOneParam("getenv", env_key, &env_value) || Z_TYPE(env_value) != IS_STRING) {
return "";
}

std::string env_value_str = Z_STRVAL_P(&env_value);
zval_ptr_dtor(&env_value);

AIKIDO_LOG_DEBUG("laravel_env[%s] = %s\n", env_key.c_str(), env_value_str.c_str());
return env_value_str;
}

std::string GetSystemEnvVariable(const std::string& env_key) {
const char* env_value = getenv(env_key.c_str());
if (!env_value) return "";
AIKIDO_LOG_DEBUG("env[%s] = %s\n", env_key.c_str(), env_value);
return env_value;
}

std::string GetEnvVariable(const std::string& env_key) {
std::string env_value = GetSystemEnvVariable(env_key);
if (env_value.empty()) {
return GetLaravelEnvVariable(env_key);
}
return env_value;
}

std::string GetEnvString(const std::string& env_key, const std::string default_value) {
std::string env_value = GetEnvVariable(env_key.c_str());
std::string env_value = GetEnvVariable(env_key);
if (!env_value.empty()) {
return env_value;
}
return default_value;
}

bool GetEnvBool(const std::string& env_key, bool default_value) {
std::string env_value = GetEnvVariable(env_key.c_str());
std::string env_value = GetEnvVariable(env_key);
if (!env_value.empty()) {
return (env_value == "1" || env_value == "true");
}
Expand Down
2 changes: 2 additions & 0 deletions lib/php-extension/HandleShouldBlockRequest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ ZEND_FUNCTION(should_block_request) {
return;
}

requestProcessor.LoadConfigOnce();

if (!GetBlockingStatus()) {
return;
}
Expand Down
2 changes: 2 additions & 0 deletions lib/php-extension/HandleUsers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ ZEND_FUNCTION(set_user) {
RETURN_BOOL(false);
}

requestProcessor.LoadConfigOnce();

char *id;
size_t id_len;
char *name;
Expand Down
5 changes: 5 additions & 0 deletions lib/php-extension/PhpWrappers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ bool CallPhpEcho(std::string message) {
}

bool CallPhpFunction(std::string function_name, unsigned int params_number, zval* params, zval* return_value, zval* object) {
if (!object && !zend_hash_str_exists(CG(function_table), function_name.c_str(), function_name.size())) {
AIKIDO_LOG_INFO("Function name '%s' does not exist!\n", function_name.c_str());
return false;
}

zval _function_name;
zend_string* _function_name_str = zend_string_init(function_name.c_str(), function_name.length(), 0);
if (!_function_name_str) {
Expand Down
17 changes: 17 additions & 0 deletions lib/php-extension/RequestProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
RequestProcessor requestProcessor;

std::string RequestProcessor::GetInitData() {
LoadEnvironment();

json initData = {
{"token", AIKIDO_GLOBAL(token)},
{"log_level", AIKIDO_GLOBAL(log_level_str)},
Expand Down Expand Up @@ -96,11 +98,13 @@ bool RequestProcessor::Init() {

RequestProcessorInitFn requestProcessorInitFn = (RequestProcessorInitFn)dlsym(libHandle, "RequestProcessorInit");
this->requestProcessorContextInitFn = (RequestProcessorContextInitFn)dlsym(libHandle, "RequestProcessorContextInit");
this->requestProcessorConfigUpdateFn = (RequestProcessorConfigUpdateFn)dlsym(libHandle, "RequestProcessorConfigUpdate");
this->requestProcessorOnEventFn = (RequestProcessorOnEventFn)dlsym(libHandle, "RequestProcessorOnEvent");
this->requestProcessorGetBlockingModeFn = (RequestProcessorGetBlockingModeFn)dlsym(libHandle, "RequestProcessorGetBlockingMode");
this->requestProcessorUninitFn = (RequestProcessorUninitFn)dlsym(libHandle, "RequestProcessorUninit");
if (!requestProcessorInitFn ||
!this->requestProcessorContextInitFn ||
!this->requestProcessorConfigUpdateFn ||
!this->requestProcessorOnEventFn ||
!this->requestProcessorGetBlockingModeFn ||
!this->requestProcessorUninitFn) {
Expand Down Expand Up @@ -138,11 +142,24 @@ bool RequestProcessor::RequestInit() {
return true;
}

void RequestProcessor::LoadConfigOnce() {
if (this->configReloaded) {
return;
}

AIKIDO_LOG_INFO("Reloading Aikido config...\n");
std::string initJson = this->GetInitData();
this->requestProcessorConfigUpdateFn(GoCreateString(initJson));
this->configReloaded = true;
}

void RequestProcessor::RequestShutdown() {
if (!request.Init()) {
AIKIDO_LOG_WARN("Failed to initialize the current request!\n");
return;
}

LoadConfigOnce();
SendPostRequestEvent();
requestInitialized = false;
}
Expand Down
4 changes: 4 additions & 0 deletions lib/php-extension/include/RequestProcessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

typedef GoUint8 (*RequestProcessorInitFn)(GoString initJson);
typedef GoUint8 (*RequestProcessorContextInitFn)(ContextCallback);
typedef GoUint8 (*RequestProcessorConfigUpdateFn)(GoString initJson);
typedef char* (*RequestProcessorOnEventFn)(GoInt eventId);
typedef int (*RequestProcessorGetBlockingModeFn)();
typedef void (*RequestProcessorUninitFn)();
Expand All @@ -10,8 +11,10 @@ class RequestProcessor {
private:
bool initFailed = false;
bool requestInitialized = false;
bool configReloaded = false;
void* libHandle = nullptr;
RequestProcessorContextInitFn requestProcessorContextInitFn = nullptr;
RequestProcessorConfigUpdateFn requestProcessorConfigUpdateFn = nullptr;
RequestProcessorOnEventFn requestProcessorOnEventFn = nullptr;
RequestProcessorGetBlockingModeFn requestProcessorGetBlockingModeFn = nullptr;
RequestProcessorUninitFn requestProcessorUninitFn = nullptr;
Expand All @@ -29,6 +32,7 @@ class RequestProcessor {
bool RequestInit();
bool SendEvent(EVENT_ID eventId, std::string& output);
bool IsBlockingEnabled();
void LoadConfigOnce();
void RequestShutdown();
void Uninit();

Expand Down
2 changes: 1 addition & 1 deletion lib/php-extension/include/php_aikido.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
extern zend_module_entry aikido_module_entry;
#define phpext_aikido_ptr &aikido_module_entry

#define PHP_AIKIDO_VERSION "1.0.98"
#define PHP_AIKIDO_VERSION "1.0.99"

#if defined(ZTS) && defined(COMPILE_DL_AIKIDO)
ZEND_TSRMLS_CACHE_EXTERN()
Expand Down
6 changes: 3 additions & 3 deletions lib/request-processor/aikido_types/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@ package aikido_types

type EnvironmentConfigData struct {
SocketPath string `json:"socket_path"` // '/run/aikido-{version}/aikido-{datetime}-{randint}.sock'
LogLevel string `json:"log_level"` // default: 'INFO'
SAPI string `json:"sapi"` // '{php-sapi}'
TrustProxy bool `json:"trust_proxy"` // default: true
LocalhostAllowedByDefault bool `json:"localhost_allowed_by_default"` // default: true
CollectApiSchema bool `json:"collect_api_schema"` // default: false
CollectApiSchema bool `json:"collect_api_schema"` // default: true
}

type AikidoConfigData struct {
Token string `json:"token"` // default: ''
LogLevel string `json:"log_level"` // default: 'WARN'
Blocking bool `json:"blocking"` // default: false
TrustProxy bool `json:"trust_proxy"` // default: true
LocalhostAllowedByDefault bool `json:"localhost_allowed_by_default"` // default: true
CollectApiSchema bool `json:"collect_api_schema"` // default: false
CollectApiSchema bool `json:"collect_api_schema"` // default: true
}

type RateLimiting struct {
Expand Down
17 changes: 12 additions & 5 deletions lib/request-processor/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ import (
"main/log"
)

func ReloadAikidoConfig(initJson string) {
err := json.Unmarshal([]byte(initJson), &globals.AikidoConfig)
if err != nil {
panic(fmt.Sprintf("Error parsing JSON to AikidoConfig: %s", err))
}

if err := log.SetLogLevel(globals.AikidoConfig.LogLevel); err != nil {
panic(fmt.Sprintf("Error setting log level: %s", err))
}
}

func Init(initJson string) {
globals.CloudConfig.Block = -1

Expand All @@ -15,15 +26,11 @@ func Init(initJson string) {
panic(fmt.Sprintf("Error parsing JSON to EnvironmentConfig: %s", err))
}

err = json.Unmarshal([]byte(initJson), &globals.AikidoConfig)
if err != nil {
panic(fmt.Sprintf("Error parsing JSON to AikidoConfig: %s", err))
}

if globals.EnvironmentConfig.SocketPath == "" {
panic("Socket path not set!")
}

ReloadAikidoConfig(initJson)
log.Init()
}

Expand Down
2 changes: 1 addition & 1 deletion lib/request-processor/globals/globals.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ var CloudConfig CloudConfigData
var CloudConfigMutex sync.Mutex

const (
Version = "1.0.98"
Version = "1.0.99"
)
2 changes: 1 addition & 1 deletion lib/request-processor/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ toolchain go1.23.3

require (
github.com/stretchr/testify v1.10.0
google.golang.org/grpc v1.68.0
google.golang.org/grpc v1.68.1
google.golang.org/protobuf v1.34.2
)

Expand Down
2 changes: 2 additions & 0 deletions lib/request-processor/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E=
google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0=
google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA=
google.golang.org/grpc v1.68.1 h1:oI5oTa11+ng8r8XMMN7jAOmWfPZWbYpCFaMUTACxkM0=
google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe00waw=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
Expand Down
6 changes: 3 additions & 3 deletions lib/request-processor/grpc/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func Init() {

log.Debugf("Current connection state: %s\n", conn.GetState().String())

sendAikidoConfig()
SendAikidoConfig()
startCloudConfigRoutine()
}

Expand All @@ -43,15 +43,15 @@ func Uninit() {
}

/* Send Aikido Config to Aikido Agent via gRPC */
func sendAikidoConfig() {
func SendAikidoConfig() {
if client == nil {
return
}

ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()

_, err := client.OnConfig(ctx, &protos.Config{Token: globals.AikidoConfig.Token, LogLevel: globals.EnvironmentConfig.LogLevel,
_, err := client.OnConfig(ctx, &protos.Config{Token: globals.AikidoConfig.Token, LogLevel: globals.AikidoConfig.LogLevel,
Blocking: globals.AikidoConfig.Blocking, LocalhostAllowedByDefault: globals.AikidoConfig.LocalhostAllowedByDefault,
CollectApiSchema: globals.AikidoConfig.CollectApiSchema})
if err != nil {
Expand Down
4 changes: 0 additions & 4 deletions lib/request-processor/log/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,6 @@ func SetLogLevel(level string) error {
}

func Init() {
if err := SetLogLevel(globals.EnvironmentConfig.LogLevel); err != nil {
panic(fmt.Sprintf("Error setting log level: %s", err))
}

if globals.EnvironmentConfig.SAPI == "cli" {
cliLogging = true
return
Expand Down
Loading

0 comments on commit 8920e07

Please sign in to comment.