Last active
August 29, 2015 14:03
-
-
Save dmlogic/a662c683052bb755b750 to your computer and use it in GitHub Desktop.
Securing Angular with Laravel
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php namespace MyApp\Response; | |
use Cookie; | |
use Request; | |
use Session; | |
use Symfony\Component\HttpFoundation\Cookie as SymfonyCookie; | |
trait AngularTrait { | |
/** | |
* Sends HTTP headers. | |
* | |
* @return Response | |
*/ | |
public function sendHeaders() | |
{ | |
$this->setAngularCookie(); | |
return parent::sendHeaders(); | |
} | |
/** | |
* Creates an AngularJS XSRF cookie on the first GET request without one | |
*/ | |
protected function setAngularCookie() | |
{ | |
// This is only relevant for an AJAX GET request | |
if(!Request::ajax() || !Request::isMethod('get')) { | |
return; | |
} | |
// If we have an existing cookie, don't make another | |
$existing = Cookie::get('XSRF-TOKEN'); | |
if(!is_null($existing)) { | |
return; | |
} | |
// We'll use a simple hash of the existing session token | |
$value = md5( Session::token() ); | |
// Add the cookie to our response | |
$this->withCookie( new SymfonyCookie('XSRF-TOKEN', $value, 0, $path = '/',null, Request::secure(),false) ); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
'aliases' => array( | |
// Replace the existing one | |
‘Response’ => ‘MyApp\Response\Facade’. | |
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php namespace MyApp\Response; | |
use Illuminate\Support\Contracts\ArrayableInterface; | |
use Illuminate\Support\Facades\Response as IlluminateFacade; | |
class Facade extends IlluminateFacade { | |
/** | |
* Return a new response from the application. | |
* | |
* @param string $content | |
* @param int $status | |
* @param array $headers | |
* @return MyApp\Response\ | |
*/ | |
public static function make($content = '', $status = 200, array $headers = array()) | |
{ | |
return new Response($content, $status, $headers); | |
} | |
/** | |
* Return a new JSON response from the application. | |
* | |
* @param string|array $data | |
* @param int $status | |
* @param array $headers | |
* @return MyApp\Response\JsonResponse | |
*/ | |
public static function json($data = array(), $status = 200, array $headers = array(), $options = 0) | |
{ | |
if ($data instanceof ArrayableInterface) | |
{ | |
$data = $data->toArray(); | |
} | |
return new JsonResponse($data, $status, $headers); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
Route::filter('ngcsrf',function($route,$request) { | |
$token = md5(Session::token()); | |
$supplied = $request->header('X-XSRF-TOKEN'); | |
if(empty($supplied) || $token != $supplied) { | |
throw new Illuminate\Session\TokenMismatchException; | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php namespace MyApp\Response; | |
use Illuminate\Support\Contracts\JsonableInterface; | |
use Illuminate\Http\JsonResponse as IlluminateResponse; | |
class JsonResponse extends IlluminateResponse { | |
use AngularTrait; | |
public function setData($data = array()) | |
{ | |
// Convert as normal | |
$this->data = $data instanceof JsonableInterface ? $data->toJson() : json_encode($data); | |
// And add the protectay thingy | |
$this->data = Response::addAngularProtection($this->data); | |
return $this->update(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php namespace MyApp\Response; | |
use Config; | |
use Request; | |
use Illuminate\Http\Response as IlluminateResponse; | |
use Illuminate\Support\Contracts\JsonableInterface; | |
class Response extends IlluminateResponse { | |
use AngularTrait; | |
/** | |
* Morph the given content into JSON. | |
* | |
* @param mixed $content | |
* @return string | |
*/ | |
protected function morphToJson($content) | |
{ | |
if ($content instanceof JsonableInterface) { | |
$content = $content->toJson(); | |
} else { | |
$content = json_encode($content); | |
} | |
return self::addAngularProtection($content); | |
} | |
/** | |
* Adds the AngularJS JSONP protection string to supplied content | |
* | |
* http://docs.angularjs.org/api/ng/service/$http#security-considerations | |
* | |
* @param string $content | |
*/ | |
public static function addAngularProtection($content) { | |
if(!Request::ajax()) { | |
return $content; | |
} | |
if(Config::get('app.angular_json_protection') === true) { | |
return ")]}',".PHP_EOL.$content; | |
} | |
return $content; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment