Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Y
yii2
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
PSDI Army
yii2
Commits
c8960168
Commit
c8960168
authored
Dec 26, 2013
by
Qiang Xue
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fixes #1634: Use masked CSRF tokens to prevent BREACH exploits
parent
2686403c
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
60 additions
and
3 deletions
+60
-3
CHANGELOG.md
framework/CHANGELOG.md
+1
-0
BaseHtml.php
framework/yii/helpers/BaseHtml.php
+1
-1
Request.php
framework/yii/web/Request.php
+57
-1
View.php
framework/yii/web/View.php
+1
-1
No files found.
framework/CHANGELOG.md
View file @
c8960168
...
...
@@ -31,6 +31,7 @@ Yii Framework 2 Change Log
-
Enh #1581: Added
`ActiveQuery::joinWith()`
and
`ActiveQuery::innerJoinWith()`
to support joining with relations (qiangxue)
-
Enh #1601: Added support for tagName and encodeLabel parameters in ButtonDropdown (omnilight)
-
Enh #1611: Added
`BaseActiveRecord::markAttributeDirty()`
(qiangxue)
-
Enh #1634: Use masked CSRF tokens to prevent BREACH exploits (qiangxue)
-
Enh #1641: Added
`BaseActiveRecord::updateAttributes()`
(qiangxue)
-
Enh: Added
`favicon.ico`
and
`robots.txt`
to defauly application templates (samdark)
-
Enh: Added
`Widget::autoIdPrefix`
to support prefixing automatically generated widget IDs (qiangxue)
...
...
framework/yii/helpers/BaseHtml.php
View file @
c8960168
...
...
@@ -241,7 +241,7 @@ class BaseHtml
$method
=
'post'
;
}
if
(
$request
->
enableCsrfValidation
&&
!
strcasecmp
(
$method
,
'post'
))
{
$hiddenInputs
[]
=
static
::
hiddenInput
(
$request
->
csrfVar
,
$request
->
getCsrfToken
());
$hiddenInputs
[]
=
static
::
hiddenInput
(
$request
->
csrfVar
,
$request
->
get
Masked
CsrfToken
());
}
}
...
...
framework/yii/web/Request.php
View file @
c8960168
...
...
@@ -10,6 +10,7 @@ namespace yii\web;
use
Yii
;
use
yii\base\InvalidConfigException
;
use
yii\helpers\Security
;
use
yii\helpers\StringHelper
;
/**
* The web Request class represents an HTTP request
...
...
@@ -83,6 +84,10 @@ class Request extends \yii\base\Request
* The name of the HTTP header for sending CSRF token.
*/
const
CSRF_HEADER
=
'X-CSRF-Token'
;
/**
* The length of the CSRF token mask.
*/
const
CSRF_MASK_LENGTH
=
8
;
/**
...
...
@@ -1021,6 +1026,43 @@ class Request extends \yii\base\Request
return
$this
->
_csrfCookie
->
value
;
}
private
$_maskedCsrfToken
;
/**
* Returns the masked CSRF token.
* This method will apply a mask to [[csrfToken]] so that the resulting CSRF token
* will not be exploited by [BREACH attacks](http://breachattack.com/).
* @return string the masked CSRF token.
*/
public
function
getMaskedCsrfToken
()
{
if
(
$this
->
_maskedCsrfToken
===
null
)
{
$token
=
$this
->
getCsrfToken
();
$mask
=
Security
::
generateRandomKey
(
self
::
CSRF_MASK_LENGTH
);
$this
->
_maskedCsrfToken
=
base64_encode
(
$mask
.
$this
->
xorTokens
(
$token
,
$mask
));
}
return
$this
->
_maskedCsrfToken
;
}
/**
* Returns the XOR result of two strings.
* If the two strings are of different lengths, the shorter one will be padded to the length of the longer one.
* @param string $token1
* @param string $token2
* @return string the XOR result
*/
private
function
xorTokens
(
$token1
,
$token2
)
{
$n1
=
StringHelper
::
byteLength
(
$token1
);
$n2
=
StringHelper
::
byteLength
(
$token2
);
if
(
$n1
>
$n2
)
{
$token2
=
str_pad
(
$token2
,
$n1
,
$token2
);
}
elseif
(
$n1
<
$n2
)
{
$token1
=
str_pad
(
$token1
,
$n2
,
$token1
);
}
return
$token1
^
$token2
;
}
/**
* @return string the CSRF token sent via [[CSRF_HEADER]] by browser. Null is returned if no such header is sent.
*/
...
...
@@ -1072,6 +1114,20 @@ class Request extends \yii\base\Request
$token
=
$this
->
getPost
(
$this
->
csrfVar
);
break
;
}
return
$token
===
$trueToken
||
$this
->
getCsrfTokenFromHeader
()
===
$trueToken
;
return
$this
->
validateCsrfTokenInternal
(
$token
,
$trueToken
)
||
$this
->
validateCsrfTokenInternal
(
$this
->
getCsrfTokenFromHeader
(),
$trueToken
);
}
private
function
validateCsrfTokenInternal
(
$token
,
$trueToken
)
{
$token
=
base64_decode
(
$token
);
$n
=
StringHelper
::
byteLength
(
$token
);
if
(
$n
<=
self
::
CSRF_MASK_LENGTH
)
{
return
false
;
}
$mask
=
StringHelper
::
byteSubstr
(
$token
,
0
,
self
::
CSRF_MASK_LENGTH
);
$token
=
StringHelper
::
byteSubstr
(
$token
,
self
::
CSRF_MASK_LENGTH
,
$n
-
self
::
CSRF_MASK_LENGTH
);
$token
=
$this
->
xorTokens
(
$mask
,
$token
);
return
$token
===
$trueToken
;
}
}
framework/yii/web/View.php
View file @
c8960168
...
...
@@ -388,7 +388,7 @@ class View extends \yii\base\View
$request
=
Yii
::
$app
->
getRequest
();
if
(
$request
instanceof
\yii\web\Request
&&
$request
->
enableCsrfValidation
)
{
$lines
[]
=
Html
::
tag
(
'meta'
,
''
,
[
'name'
=>
'csrf-var'
,
'content'
=>
$request
->
csrfVar
]);
$lines
[]
=
Html
::
tag
(
'meta'
,
''
,
[
'name'
=>
'csrf-token'
,
'content'
=>
$request
->
getCsrfToken
()]);
$lines
[]
=
Html
::
tag
(
'meta'
,
''
,
[
'name'
=>
'csrf-token'
,
'content'
=>
$request
->
get
Masked
CsrfToken
()]);
}
if
(
!
empty
(
$this
->
linkTags
))
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment