Configuration of PHP Expose (PHPIDS) - php

I was looking for a PHP Intrusion Detection System and it seems like
Exposed was a good candidate. The latest
documentation is here.
I am having some problems understanding the installing of Exposed, so here is my question.
Say I want to add this layer of security on a file called users.php, I have read the documentation and my file would then look like this:
<?php
// <EXSPOSED_SNIPPET_LOGIC>
// Enable loader, mocklogger
require 'vendor/autoload.php';
// Initiate Monolog
use Monolog\Logger;
use Monolog\Handler\FirePHPHandler;
ini_set('display_errors', 0);
// The data to filter
$data = array(
'GET' => $_GET,
'POST' => $_POST,
'COOKIE' => $_COOKIE
);
// Load filters
$filters = new \Expose\FilterCollection();
$filters->load();
// Initiate logger
$logger = new Logger('my_logger');
$logger->pushHandler(new StreamHandler(__DIR__.'/__exposed.log', Logger::DEBUG));
$logger->pushHandler(new FirePHPHandler());
// Run tests
$manager = new \Expose\Manager($filters, $logger);
$manager->run($data);
// Define a threatlevel to act upon
$threatlevel = 12;
if( $manager->getImpact() >= $threatlevel ){
// **001**
// We are most likely under attack or atleast we should pay attention
// What do we log here, how do we log it and do we send email to alert?
$reports = $manager->getReports();
print_r($reports);
} else {
// **002**
// Assuming there is normal activity
// Should we log anything here, and if so what?
}
// </EXSPOSED_SNIPPET_LOGIC>
// Here comes the original code belonging to users.php
/* ... */
?>
The code will now write all request to a logfile from the line:
$logger->pushHandler(new StreamHandler(__DIR__.'/__exposed.log', Logger::DEBUG));
Is this needed, this will be a huge amount of data in a short while and can I even use the log for any purposa at a later time?
I also wonder on the Monolog Handler, this line:
use Monolog\Handler\FirePHPHandler;
...
$logger->pushHandler(new FirePHPHandler());
What does this code even do? I cannot see any difference in output to screen with or without it, the logfile also seems identical with or without this.
My main questions are on the lines ** 001 ** AND ** 002 ** in comments, that is, if I have understood the concept correctly hopefully my questions are not missing the target here.
It seems to me that checking the input and when a certain level is triggered, a certrain logging part and tracking should be enabled. Maby this is not part of Exposed? If you have some input on finalizing this integration code I would be very greatful.
Thank you in advance

Related

Modify log format on runtime using Monolog and Laravel

I need write a customlog on laravel 5.3, and modify on runtime for add some extra information.
So far I have managed to do it, but the code does not work because what I can do is add a new instance of the log, which duplicates the lines in each modification of the format.
My handicap is that I do not know how to return or if this is possible, the current handler of the logging system, and simply pass it the format modification.
The code below allows me to modify the format line, but only once.
If I run it again, start duplicating the lines, and what is not like, create the handler in another way, or use the existing one that would be appropriate.
$maxFiles = config('app.log_max_files');
$path = storage_path('/logs/cprsync.log');
// Really I don't need this because this are on Laravel App, but with this method y can create a $handler for modify format
$handler = new RotatingFileHandler($path, is_null($maxFiles) ? 5 : $maxFiles, config('app.log_level'));
(is_null(config('cprsync.activejob'))) ? $job = '' : $job=' ['.config('cprsync.activejob').']';
$logFormat = "[%datetime%] [%level_name%]".$job.": %message% %context% %extra%\n";
$formatter = new LineFormatter($logFormat,null,true,true);
$handler->setFormatter($formatter); // What I really want is to make this change ...
// Push handler
$log->getMonolog()->pushHandler($handler);
I don't know if it's the prettiest (like in Symfony you can just put some YAML rules in the services.yml and you've changed your log format), but this seems to be a very valid option and basically builds on what you're doing already:
http://laravel-tricks.com/tricks/monolog-for-custom-logging
TL;DR: Create a custom logging class with a function write() that basically contains the code OP has posted. Then add that class to your facades and you can log with MyCustomLogger::write($message);
EDIT: This isn't really what OP requested, since this doesn't change the format on runtime.

Laravel 5.3 changing logfiles for specific console commands

There are two noisy console commands in my Laravel 5.3 app that I want to keep logs for but would prefer to have them write to a different log file from the rest of the system.
Currently my app writes logs to a file configured in bootstrap/app.php using $app->configureMonologUsing(function($monolog) { ...
Second prize is writing all console commands to another log file, but ideally just these two.
I tried following these instructions (https://blog.muya.co.ke/configure-custom-logging-in-laravel-5/ and https://laracasts.com/discuss/channels/general-discussion/advance-logging-with-laravel-and-monolog) to reroute all console logs to another file but it did not work and just caused weird issues in the rest of the code.
If this is still the preferred method in 5.3 then I will keep trying, but was wondering if there was newer method or a method to only change the file for those two console commands.
They are two approaches you could take
First, you could use Log::useFiles or Log::useDailyFiles like suggests here.
Log::useDailyFiles(storage_path().'/logs/name-of-log.log');
Log::info([info to log]);
The downside of this approach is that everything will still be log in your default log file because the default Monolog is executed before your code.
Second, to avoid to have everything in your default log, you could overwrite the default logging class. An exemple of this is given here. You could have a specific log file for let's say Log::info() and all the others logs could be written in your default file. The obvious downside of this approach is that it requires more work and code maintenance.
This is possible but first you need to remove existing handlers.
Monolog already has had some logging handlers set, so you need to get rid of those with $monolog->popHandler();. Then using Wistar's suggestion a simple way of adding a new log is with $log->useFiles('/var/log/nginx/ds.console.log', $level='info');.
public function fire (Writer $log)
{
$monolog = $log->getMonolog();
$monolog->popHandler();
$log->useFiles('/var/log/nginx/ds.console.log', $level='info');
$log->useFiles('/var/log/nginx/ds.console.log', $level='error');
...
For multiple handlers
If you have more than one log handler set (if for example you are using Sentry) you may need to pop more than one before the handlers are clear. If you want to keep a handler, you need to loop through all of them and then readd the ones you wanted to keep.
$monolog->popHandler() will throw an exception if you try to pop a non-existant handler so you have to jump through hoops to get it working.
public function fire (Writer $log)
{
$monolog = $log->getMonolog();
$handlers = $monolog->getHandlers();
$numberOfHandlers = count($handlers);
$saveHandlers = [];
for ($idx=0; $idx<$numberOfHandlers; $idx++)
{
$handler = $monolog->popHandler();
if (get_class($handler) !== 'Monolog\Handler\StreamHandler')
{
$saveHandlers[] = $handler;
}
}
foreach ($saveHandlers as $handler)
{
$monolog->pushHandler($handler);
}
$log->useFiles('/var/log/nginx/ds.console.log', $level='info');
$log->useFiles('/var/log/nginx/ds.console.log', $level='error');
...
For more control over the log file, instead of $log->useFiles() you can use something like this:
$logStreamHandler = new \Monolog\Handler\StreamHandler('/var/log/nginx/ds.console.log');
$pid = getmypid();
$logFormat = "%datetime% $pid [%level_name%]: %message%\n";
$formatter = new \Monolog\Formatter\LineFormatter($logFormat, null, true);
$logStreamHandler->setFormatter($formatter);
$monolog->pushHandler($logStreamHandler);

How to Turn off Debugging Logs with Monolog

I'm using Monolog in a project, it's not Symfony, just my own application that uses the stand-alone Monolog composer package.
What I'd like to do is programmatically turn off debugging logs. I'm writing to a log file and I'm using the Monolog::StreamHandler. I'm controlling whether the application is in debug mode or not with a Configuration class that gets the debug value from a configuration file. So when someone changes that value to debugging is false, debug logging should turn off.
I felt like the easiest way to do this would be to extend StreamHandler and override StreamHandler's write method like this.
class DurpLogger extends StreamHandler {
protected function write(array $record) {
if ($this->getLevel() == Durp::Debug && !Configuration::debug()) {
return;
}
parent::write($record);
}
}
So if a log request comes in and the log level for the handler is set to DEBUG and the application's Configuration::debug() is FALSE then just return without writing the log message. Otherwise, StreamHandler will do its thing.
I'm wondering if this is the best way to use Monolog or if there's perhaps a cleaner way to do this.
I envision there being a handler in my application for DEBUG, INFO, ERROR and whatever levels I might need for my application. Perhaps it makes sense to not rely on a Configuration::debug() that can only be TRUE or FALSE, but rather a Configuration::logLevel() that will allow me to more granularly control logging output.
But even still, does extending StreamHandler make the most sense when controlling Monolog at the application level?
UPDATE
Now, I'm thinking something like this, that uses level rather than just boolean debug.
class DurpLogger extends StreamHandler {
public function __construct() {
parent::__construct(Configuration::logFile(), Configuration::logLevel());
}
protected function write(array $record) {
if (!($this->getLevel() >= Configuration::logLevel())) {
return;
}
parent::write($record);
}
}
Then I'd use it in the application like this.
class Durp {
private $logger;
public function __construct() {
$this->logger = new Logger('durp-service');
$this->logger->pushHandler(new DurpLogger());
$this->logger->addDebug('Debugging enabled');
$this->logger->addInfo('Starting Durp');
}
}
I figured the StreamHandler handles the file writing stuff, so that's why I'm extending it. And if I turn up the log level in Configuration to Logger::INFO, the "Debugging enabled" message doesn't get logged.
Open to suggestions to make this better.
A common alternative would be to use the NullHandler instead of the StreamHandler.
Maybe switch between them depending on your condition like follows:
if (!Configuration::debug()) {
$logger->pushHandler(new \Monolog\Handler\NullHandler());
}
I would like to give you an example that is more adapted to your usage,
but I need to see some code in order to know how you use it.
Update
For the question about default format, the empty [] at end represent the extra data that can be added with log entries.
From #Seldaek (Monolog's owner) :
The default format of the LineFormatter is:
"[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n". the username/age is the context, and extra that is typically empty results in this empty array [].
If you use processors to attach data to log records they typically write it to the extra key to avoid conflicts with context info. If it really is an issue for you you can change the default format and omit %extra%.
Edit: As of Monolog 1.11 the LineFormatter has a $ignoreEmptyContextAndExtra parameter in the constructor that lets you remove these, so you can use this:
// the last "true" here tells it to remove empty []'s
$formatter = new LineFormatter(null, null, false, true);
$handler->setFormatter($formatter);
See How not to show last bracket in a monolog log line? and Symfony2 : use Processors while logging in different files about the processors which #Seldaek is talking about.

API response - gathering errors from included classes

I'm working on a RESTful and am stuck on message gathering for returning to the user. Basically, depending on the options selected, a few classes will be included dynamically. I'll try to provide a real-world break down. We have a HTML-email-tempalte maker - depending on the template chosen a php script will be included. This script may have warnings and I need to pass them "upstream" so that the API can report them. So we have something like this ( -> = includes )
API -> HTMLGenerator -> (dynamically) template-script.php
I need the template-script to be able to report errors to the API controller so the API can report them to the API user. Not sure the best way/practice to accomplish this.
So far , my thoughts are maybe a singleton or session variable that the template-script can add messages to, then the API Controller can report them. Any thoughts?
Main API
REST create by POST to /v1/html basically just:
class API {
require($dynamic_script);
$errors = array('warnings'=>array('warning1',waring2'));
//set http header and return JSON
}
HTMLGenerator
class HTMLGenerator {
//basically some wrappers for junior / non-programmers
function addHeading($text) {
//Add a header and do some checks.
if(strlen($text) > $warnTooLong )
HTMLErrors::addWarning("Message");
}
}
Dynamic Script
$h = new HTMLGenerator();
$h->addHeader($text);
$h->addImage($imageUrl);
You need to use a custom error handler.
See this link - http://php.net/manual/en/function.set-error-handler.php
It allows us to handle a error that might be thrown to capture it and process it. So, when you capture it, you can pass this to the parent class and furthur upstream for further processing.
Global object would work, set_error_handler too, but these are just hacks. The cleanest option is to modify your app elements to do what they are suppose to do - return those messages.
These shouldn't be too hard to do:
function myOldFunction($param1, $param2)
{
// do something
}
modify this way:
function myOldFunction($param1, $param2, array &$messages = array())
{
// do something
$messages[] = 'hey mama, i\'m on stack overflow!';
}
usage:
$messages = array();
myOldFunction(1, 2, $messages);
print_r($messages);

log4php logger->setLevel() doesn't work

Not sure why this very simple thing doesn't work -
$logger = Logger::getLogger("test");
$logger->setLevel(LoggerLevel::getLevelWarn());
$logger->debug("debug");
$logger->info("info");
$logger->warn("warn");
This will print:
DEBUG - debug
INFO - info
WARN - warn
I must be doing something obviously stupid! I would assume that neither the debug nor info logging would come through with the setLevel() to warn was present.
Thoughts?
I would like to have multiple loggers that each log at different levels. Not sure why this is so hard...
If you check the created Logger object (after you initialize it with Logger::getLogger("test");), you'll see that it already has a parent Logger, object(LoggerRoot). This object has its level set to DEBUG, and that's actually the logger that prints the debug and info messages.
One possible approach is to use a RootLogger instead:
$logger = Logger::getRootLogger();
$logger->setLevel(LoggerLevel::getLevelWarn());
$logger->debug("debug");
$logger->info("info");
$logger->warn("warn");
Another approach is to configure rootLogger so that it will log only messages of some very high level (FATAL), and let your loggers to set levels appropriate to them. But in that case you need to add your own appenders to those (it's appenders that do the logging job; loggers just manage them). Again, one possible approach:
$rootLogger = Logger::getRootLogger();
$rootLogger->setLevel(LoggerLevel::getLevelFatal());
$logger = Logger::getLogger('some');
$logger->addAppender($rootLogger->getAppender('default'));
$logger->setLevel(LoggerLevel::getLevelInfo());
$logger->debug('debug'); // won't print
$logger->info('info'); // will be printed
$logger->warn('warn'); // will be printed too
$logger->fatal('fatal dup'); // will be printed TWICE:
// with $logger, then with $rootLogger
$logger->setAdditivity(false); // switching off log event propagation
$logger->fatal('fatal once'); // will be printed ONCE
But it you actually need a complex hierarchy of loggers, I'd highly suggest configuring them all at once, following the approach described in this section of log4php documentation.

Categories