Monday, July 27, 2015

Release v0.5

I've added release v0.5 on GitHub containing all the changes presented in the last posts:
-unique point for checking authorization
-TinyMCE integratation
-pagination fixing
-basic data validation and escaping

Friday, July 17, 2015

Unique point of checking authorization

In a previous post I listed "Unique point to check authorization" as @todo.

I will tell you now the reason, while  playing with "myFrontController" I noticed that links like http://myfrontcontroller/admin/new-post can be accessed without being logged in. An unwanted intruder knowing that path can post something like "I hacked your site!"


Solution:
I have verifications of authentication scattered in different places, for this reason I missed to check this situation. It would be nice to have one point where all requests should be checked.
I added in router.xml a new field called "levelOfSecurity". If the value of this field is "all" accessing a certain page does not require authentication. If "levelOfSecurity" is set to "admin" than a verification is made.

A path in router.xml looks now like this:

        <path>/edit/post/{slug}</path>
        <levelOfSecurity>admin</levelOfSecurity>
        <path_regexp>/\/edit\/post\/[\w\-]+/i</path_regexp>
        <controllerClass>Blog</controllerClass>
        <action>editPost</action>

A new static method was added to LoginUser class:

   public static function accessAllowed($levelOfSecurity)
    { 
        $flag=false;
        if ($levelOfSecurity=='all') {
            $flag=true;
            return $flag;
        }else {
            $flag=self::ValidateLoginAdmin();
            return $flag;
        }
       
    }

In FrontController::findPath() method after checking if a path exists also it is verified the access authorisation:

if (($route->path==$path) {
    if (LoginUser::accessAllowed($route->levelOfSecurity)))

TinyMCE integration with PHP

As you could saw my blog posts on the  "myFrontController" platform are like "adadafa fadfadfad". But from now on I want to be able to use text formatting, for this reason I want to integrate a Javascript editor with my code.
After a quick search I picked TinyMCE:

TinyMCE is a platform independent web based Javascript HTML WYSIWYG editor control released as Open Source under LGPL. TinyMCE has the ability to convert HTML TEXTAREA fields or other HTML elements to editor instances.

Installation:

I inserted this code beloe in the <head> of the \template\main_template.php file. As you can see I am using TinyMCE from a CDN.

    <script type="text/javascript" src="//tinymce.cachefly.net/4.0/tinymce.min.js"></script>
    <script type="text/javascript">
       tinymce.init({
      
           selector: "textarea",
       plugins: [
           "advlist autolink lists link image charmap print preview anchor",
           "searchreplace visualblocks code fullscreen",
          "insertdatetime media table contextmenu paste "
        ],
        toolbar: "insertfile undo redo | styleselect | bold italic | alignleft aligncenter      alignright alignjustify | bullist numlist outdent indent | link image"
    });


I did some  tests, and it works nicely, I can now insert images or videos hosted somewhere on internet. TinyMCE offers some paid extension for uploading files on the server(with a server side code to handle those) but I am not going to try that.




Wednesday, July 15, 2015

Basic security measures and Apache logs

.htaccess


I checked and I could access the .php files found in base directory or in order sub folders. I added to the .htaccess the following lines:
   
    #redirect all .php files request to index.php
    RewriteRule ^(.*)\.php index.php [NC]


Later edit:  I tried to access http://myFrontController/config/route.xml  and surprise, it was displayed on screen. So now I decided to  redirect to index.php all file request, whatever extension they have

        RewriteRule ^(.*)\.* index.php [NC]


Unique point to check authorization

@todo

Validating and escaping  input data

I 've read some articles on this topic, there different approaches, the one that I liked most was :  Filter Input, Escape Output. From this discussion on stackoverflow:


"Here are the coding conventions I use:
  • values in $_POST, $_GET, $_REQUEST, etc. should not be escaped and should always be considered unsafe
  • values should be validated1 before being written to database or stored in $_SESSION
  • values expected to be numeric or boolean should be sanitized2 before being written to database or stored in $_SESSION
  • trust that numeric and boolean values from database and $_SESSION are indeed numeric or boolean
  • string values should be SQL-escaped before being used directly in any SQL query (non-string values should be sanitized2) or use prepared statements
  • string values should be HTML-escaped before being used in HTML output (non-string values should be sanitized2)
  • string values should be percent-encoded before being used in query strings (non-string values should be sanitized2)
  • use a variable naming convention (such as *_url, *_html, *_sql) to store transformed data
Terminology
For my purposes here, this is how I define the terms used above.
  1. to validate means to confirm any assumptions being made about the data such as having a specific format or required fields having a value
  2. to sanitize means to confirm values are exactly as expected (i.e. $id_num should contain nothing but digits)
Summary
In general (there may be some exceptions), I'd recommend the following:
  • use validate filters on input
  • use sanitize filters on output
  • remember TIMTOWDI - For example, I prefer htmlspecialchars() (which has more options) over FILTER_SANITIZE_FULL_SPECIAL_CHARS or FILTER_SANITIZE_SPECIAL_CHARS (which escapes line breaks)"
What I did

1. Validating data entered in the login form

- new class to store validation methods \validation\Valid.class.php
- use a regex to validate user and password:  '/^[a-zA-Z0-9_-]{3,16}$/i' (white list validation). A resource for validation regex: https://www.owasp.org/index.php/OWASP_Validation_Regex_Repository
- use the validation method in Admin.class.php :

    if (Validation::userAndPass($_POST['username'],$_POST['password']))

If the input is not valid show Javascript pop up message and redirect to login page (I know, I am not checking to see if Javascript is enabled)

    $message = "The entered value is not valid.";
    echo "<script type='text/javascript'>alert('$message');window.location = '/admin';</script>";



I've read about the filter_var() function from PHP and the types of filters available and I feel this regex is doing just fine for the job.
More on this :  http://code.tutsplus.com/tutorials/getting-clean-with-php--net-6732

The other places where data enters in the application are the new entry post/edit post form. I will apply "htmlentities()" function
before saving them on the Database.
-in BlogModel::newPost and BlogModel::updatePost I apply htmlentities()

  $result=$db->newPost(htmlentities($Author), htmlentities($Category), htmlentities($Text), htmlentities($Title), $Slug)

- in Blog::renderPost I decode the content of the post:

$new_content.= "<tr>".html_entity_decode($row['ActualPost'])."</tr></br>";

2. Use prepared statements and parameterized queries. - I am already doing that, I should just set connection attributes as mentioned here: http://stackoverflow.com/questions/60174/how-can-i-prevent-sql-injection-in-php

"What is mandatory however is the first setAttribute() line, which tells PDO to disable emulated prepared statements and use real prepared statements. This makes sure the statement and the values aren't parsed by PHP before sending it to the MySQL server (giving a possible attacker no chance to inject malicious SQL)."

            $db_conn = new PDO('mysql:host=localhost;dbname=myblog', $user, $pass);
            $db_conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
            $db_conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);



Saving Database user and password somewhere safe

As usually StackOverflow offers the answers: http://stackoverflow.com/questions/97984/how-to-secure-database-passwords-in-php
From the list of answers I picked on the below option:

If you're hosting on someone else's server and don't have access outside your webroot, you can always put your password and/or database connection in a file and then lock the file using a .htaccess:
 
<files mypasswdfile>
order allow,deny
deny from all
</files>

As I am already denying access to any .php file I didn't added anything else to the .htaccess

Also for the future:  "The usual solution is to move the password out of source-code into a configuration file. Then leave administration and securing that configuration file up to your system administrators. That way developers do not need to know anything about the production passwords, and there is no record of the password in your source-control."


 Apache logs


You can find those in the apache \logs on Windows machines.

1. access.log gives you information about whar  URIs were requested, by whom, and the answer from server, so you can see the URLs attacks:

The log file entries produced in CLF will look something like this:

127.0.0.1 - frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326 
Each part of this log entry is described below(source http://httpd.apache.org/docs/2.2/logs.html ):
127.0.0.1 (%h)
This is the IP address of the client (remote host) which made the request to the server. 
- (%l)
The "hyphen" in the output indicates that the requested piece of information is not available. In this case, the information that is not available is the RFC 1413 identity of the client determined by identd on the clients machine. This information is highly unreliable and should almost never be used except on tightly controlled internal networks. 
frank (%u)
This is the userid of the person requesting the document as determined by HTTP authentication. This value should not be trusted because the user is not yet authenticated. If the document is not password protected, this part will be "-" just like the previous one.
[10/Oct/2000:13:55:36 -0700] (%t)
The time that the request was received. The format is:
[day/month/year:hour:minute:second zone]
"GET /apache_pb.gif HTTP/1.0" (\"%r\")
The request line from the client is given in double quotes. The request line contains a great deal of useful information. First, the method used by the client is GET. Second, the client requested the resource /apache_pb.gif, and third, the client used the protocol HTTP/1.0. It is also possible to log one or more parts of the request line independently. For example, the format string "%m %U%q %H" will log the method, path, query-string, and protocol, resulting in exactly the same output as "%r".
200 (%>s)
This is the status code that the server sends back to the client. This information is very valuable, because it reveals whether the request resulted in a successful response (codes beginning in 2), a redirection (codes beginning in 3), an error caused by the client (codes beginning in 4), or an error in the server (codes beginning in 5). The full list of possible status codes can be found in the HTTP specification (RFC2616 section 10).
2326 (%b)
The last part indicates the size of the object returned to the client, not including the response headers. If no content was returned to the client, this value will be "-". To log "0" for no content, use %B instead.


2. error.log - in my case was a large file which NotePad++ couldn't open. I used VIM(http://www.vim.org/download.php#pc) and it worked like a charm.

The format of the error log is relatively free-form and descriptive. But there is certain information that is contained in most error log entries. For example, here is a typical message.
[Wed Oct 11 14:32:52 2000] [error] [client 127.0.0.1] client denied by server configuration: /export/home/live/ap/htdocs/test
The first item in the log entry is the date and time of the message. The second item lists the severity of the error being reported. 

Tuesday, July 14, 2015

Fix pagination bugs

Saving the current page on hard disk was a work around solution because at that moment I didn't had implemented URLs with parameters (routing with regex). This work around is OK if there is just one user surfing on the page:), because if there are more than one, they will influencing what page the other ones is seeing, and that is just wrong.

You can do a little test, open two tabs and navigate with Newer and Older buttons to see the issue.

In \config\route.xml I modified the routes to accept  URLs like /blog/3

<route name="blog page older">
        <path>/blog/{number}</path>
        <path_regexp>/\/blog\/[0-9]+$/i</path_regexp>
        <controllerClass>Blog</controllerClass>
        <action>renderPagination</action>
    </route>


    <route name="blog page newer">
        <path>/blog/{number}</path>
       <controllerClass>Blog</controllerClass>
       <action>renderPagination</action>
    </route>


The regexp is '/\/blog\/[0-9]+$/i' . To avoid a partial match,I appended a $ to the end,  '+' means more than one digit

The BlogModel has two new properties, $page_older and $page_newer which will be set after some verification, should not be lower than 1 and bigger than total number of posts divided by posts per page($per_page) .

        public function setPageNumber($current_page)
        {
            $db=new DBCon;
            $totalPostsNo=$db->countBlogPosts();
            if ($current_page<=1){
           
                $this->page_number=1;
               
            }else if ($current_page>=($totalPostsNo/$this->per_page)){
           
                $this->page_number=$current_page;
                $this->page_older=$current_page -1;
                $this->page_newer=$current_page;
           
            }else{
           
                $this->page_number=$current_page;
                $this->page_older=$current_page -1;
                $this->page_newer=$current_page +1;
            }
           
        }


Monday, July 13, 2015

Virtual hosts and relative URLs

As you probably saw, when I started my little front controller project I used absolute URLs because what it matter in the beginning was just to have a  working PHP website on my local computer.
When I copied the project to my computer at work I had to have theh same path "127.0.0.1/myFrontController/" and from this base address it was computed the relative URL to identify the route in router.xml.

As I  am getting closer to version 1.0 I need to make my website independent from where it will be deployed. In order to archive this  I will be using virtual hosts feature.
 
If you are using EasyPHP as I do, Install the module Virtual Host Manager from: http://www.easyphp.org/save-module-virtualhostsmanager-vc9-latest.php  or have look here http://www.apptools.com/phptools/virtualhost.php
 - create a virtual host called as you wish
Do some changes in the code:
- 'Location:http://127.0.0.1/myFrontController/admin/home' changed to "Location: /admin/home" in Admin.class.php 
-  edit all links to be relative
- use directly the $_SERVER['REQUEST_URI'] instead erasing "/myFrontController" in FrontController class constructor.

        $request_uri=$_SERVER['REQUEST_URI'];
        $this->relative_url=substr($request_uri, strpos($request_uri, '/', 1));
       

        replaced with:
       
        $this->relative_url=$_SERVER['REQUEST_URI'];
       

Fixing PSR2 errors with phpcbf and integration with Netbeans 8

I used my own style  formatting the code until now (I  am still using Notepad++ to edit my code, and I hit the TAB to indent  the code). I've read about the PSR-2 coding style guide and I want to follow it from now, but what  about the code already written? There is a solution for that :
PHP Code Sniffer and  PHP Code Beautifier and Fixer. On my home laptop I installed also NetBeans and I made efforts to integrate these static analysis tools with NetBeans 8 on Windows 7.

Some good articles about this topic:

http://blog.florianwolters.de/tutorial/2012/05/03/Integrate-tools-for-static-PHP-code-analyses-into-NetBeans-7.x/
https://blogs.oracle.com/netbeansphp/entry/static_code_analysis
 
 But still the mother fucker "phpcbf" was not fixing my code:

              "diff" is not recognized as an internal or external command....  



On Windows machines there is a problem with the --diff option (another reason to move to Linux), you need to specify  "--no-patch" http://stackoverflow.com/questions/24015486/fixing-psr2-errors-with-phpcbf-phar

I decided to run it form command line and not from NetBeans.  My phpcbf command to fix the errors was:


"..path.. to phpcbf.bat"  "fix" "--no-ansi" "--verbose" "--dry-run" "--no-patch" "--format=xml" "--no-interaction" "--level=psr2" "--config=sf20" "C:\Program Files (x86)\EasyPHP-DevServer-14.1VC9\data\localweb\myFrontController"

Inside the file "phpcbf.bat" you may need to add manually the path to php.exe and to phpcbf (with no extension)