Bug #75496 [NEW]: Session ID Collision happened few times
| From: | dmitry dot yeskin at gmail dot com | Date: | Tue, 07 Nov 2017 11:13:47 +0000 |
| Subject: | Bug #75496 [NEW]: Session ID Collision happened few times | ||
| Groups: | php.bugs | ||
| Request: | Send a blank email to php-bugs+get-212494@lists.php.net to get a copy of this message | ||
From: dmitry dot yeskin at gmail dot com
Operating system: Amazon OS
PHP version: 7.0.25
Package: Session related
Bug Type: Bug
Bug description:Session ID Collision happened few times
Description:
------------
Hello!
We have an e-commerce website written with Yii2 framework.
We don't modify session ids ourself. We just use session_start();
So here is what happened: we have a good traffic like 12000 unique users
in 3 hrs of mornings every day. And for last 2 weeks - we got a session
id collision 2 times. I mean - 2 customers came to website exactly at
the same second and got shared session id.
In result, they were able to see content of each other in their cart,
until they started removing that content and even made a checkout, and
then complained that ordered wrong item.
Here is data from nginx log:
--------
[ec2-user@scw ~]$ grep -r "73.111.163.135\|73.19.225.170" log.log
73.111.163.135 - - [26/Oct/2017:18:43:52 -0600] "GET
/postcard?r=26oct2017 HTTP/2.0" 200
73.19.225.170 - - [26/Oct/2017:18:43:52 -0600] "GET
/postcard?r=26oct2017 HTTP/2.0" 200
73.111.163.135 - - [26/Oct/2017:18:47:09 -0600] "POST
/postcard?r=26oct2017 HTTP/2.0" 30
73.111.163.135 - - [26/Oct/2017:18:47:09 -0600] "GET
/postcard?r=26oct2017 HTTP/2.0" 200
73.111.163.135 - - [26/Oct/2017:18:47:12 -0600] "GET /cart HTTP/2.0"
200
73.111.163.135 - - [26/Oct/2017:18:47:42 -0600] "POST /cart HTTP/2.0"
200
73.111.163.135 - - [26/Oct/2017:18:48:48 -0600] "GET /cart/checkout/
HTTP/2.0" 200
73.19.225.170 - - [26/Oct/2017:18:50:39 -0600] "POST
/postcard?r=26oct2017 HTTP/2.0" 302
73.19.225.170 - - [26/Oct/2017:18:50:39 -0600] "GET
/postcard?r=26oct2017 HTTP/2.0" 200
73.19.225.170 - - [26/Oct/2017:18:50:46 -0600] "GET /cart HTTP/2.0" 200
73.19.225.170 - - [26/Oct/2017:18:51:00 -0600] "GET /cart/remove/1
HTTP/2.0" 302
73.19.225.170 - - [26/Oct/2017:18:51:00 -0600] "GET /cart HTTP/2.0" 200
73.111.163.135 - - [26/Oct/2017:18:51:09 -0600] "POST /cart/checkout/
HTTP/2.0" 302
73.111.163.135 - - [26/Oct/2017:18:51:09 -0600] "GET
/cart/checkout/complete HTTP/2.0" 200
73.19.225.170 - - [26/Oct/2017:18:51:17 -0600] "GET /cart/checkout/
HTTP/2.0" 200
------------
You may see that both customers came to website at the same moment to
postcard page (then they clicked add to cart and proceeded to cart, and
then one of users saw wrong item there and called /cart/remove/1, then
another user completed checkout, but he bought a wrong item and then
complained to us).
For 2 weeks we got 2 similar cases.
After the first case we changed a hash entropy php settings in php.ini
so session_id is now 48 chars but it didn't help to prevent second
case.
We solved this issue by adding user_agent to session var on controller
init:
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
if (!isset($_SESSION['user_agent']) ||
empty($_SESSION['user_agent']) || $_SESSION['user_agent'] ===
Yii::$app->request->getUserAgent()) {
} else {
session_regenerate_id();
unset($_SESSION['user_agent']);
unset($_SESSION['cart']);
}
if (!isset($_SESSION['user_agent'])) {
$_SESSION['user_agent'] =
Yii::$app->request->getUserAgent();
}
But still wondered why this happens? I read in github php source code
that php must use IP address and random value for session_id generation
so it must be unique and i also read that php has some mechanisms to
prevent session_id collisions. But looks like it doesn't work
correctly.
Again - everything great for thousands users. It only happened twice for
last 2 weeks.
We dont modify session_id value ourself. We just use session_start and
work with $_SESSION variables after that. What are we doing wrong?
Is it a bug?
We have PHP 7.0.21 working as php-fpm and nginx
PS. Doing PHP coding for 20 years, and see this for the first time.
Test script:
---------------
/**
* Process adding line-item to cart
*
* @return boolean the status of addition
*/
public function addToCart() {
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
if (!isset($_SESSION['cart'])) {
//$_SESSION['cart'] = array('items' => array(),
'coupon' =>
array(), 'subtotal' => '', 'discount' => '',
'shipping' => '', 'total'
=> '');
$_SESSION['cart'] = array('items' => array(), 'coupon'
=>
array(), 'cost' => '', 'discount' => '',
'shipping' => '', 'total' =>
'');
}
$cost = ($this->price + 1 - 1); // Converting string to number
if (is_array($this->addons) && count($this->addons)>0) {
foreach ($this->addons as $addon) {
if (isset($addon['price']) &&
is_numeric($addon['price']) && !empty($addon['price'] + 1 - 1)) $cost +=
$addon['price'];
}
}
$shippingCost = 0;
if ($this->type == 'package' || $this->type == 'postcard' ||
$this->type == 'book') {
$data = $this->data;
if (isset($data['shipping']) && !empty($data['shipping'])
&&
isset($data[$data['shipping']]) && is_numeric($data[$data['shipping']])
&& !empty($data[$data['shipping']] + 1 - 1)) $shippingCost =
$data[$data['shipping']];
}
$_SESSION['cart']['items'][] = array(
'id' => $this->id,
'product_id' => $this->product_id,
'sku' => $this->sku,
'title' => $this->title,
'type' => $this->type,
'description' => $this->description,
'price' => number_format((float)$this->price, 2, '.',
''),
'picture' => $this->picture,
'data' => $this->data,
'address' => $this->address,
'addons' => $this->addons,
'cost' => number_format((float)$cost, 2, '.', ''),
'shipping' => number_format((float)$shippingCost, 2, '.',
''),
'subtotal' => number_format((float)($cost + $shippingCost),
2, '.', ''),
'draft' => $this->draft,
);
$cost = 0;
$shipping = 0;
foreach ($_SESSION['cart']['items'] as $key => $item) {
$cost += $item['cost'];
$shipping += $item['shipping'];
}
$discount = (isset($_SESSION['cart']['discount']) &&
!empty($_SESSION['cart']['discount'])) ?
$_SESSION['cart']['discount'] :
0;
$_SESSION['cart']['cost'] = number_format((float)$cost, 2,
'.',
'');
$_SESSION['cart']['shipping'] = number_format((float)$shipping,
2, '.', '');
$_SESSION['cart']['total'] = number_format((float)($cost +
$shipping - $discount), 2, '.', '');
return true;
}
--
Edit bug report at https://bugs.php.net/bug.php?id=75496&edit=1
--
Try a snapshot (PHP 5.4): https://bugs.php.net/fix.php?id=75496&r=trysnapshot54
Try a snapshot (PHP 5.5): https://bugs.php.net/fix.php?id=75496&r=trysnapshot55
Try a snapshot (trunk): https://bugs.php.net/fix.php?id=75496&r=trysnapshottrunk
Fixed in SVN: https://bugs.php.net/fix.php?id=75496&r=fixed
Fixed in release: https://bugs.php.net/fix.php?id=75496&r=alreadyfixed
Need backtrace: https://bugs.php.net/fix.php?id=75496&r=needtrace
Need Reproduce Script: https://bugs.php.net/fix.php?id=75496&r=needscript
Try newer version: https://bugs.php.net/fix.php?id=75496&r=oldversion
Not developer issue: https://bugs.php.net/fix.php?id=75496&r=support
Expected behavior: https://bugs.php.net/fix.php?id=75496&r=notwrong
Not enough info: https://bugs.php.net/fix.php?id=75496&r=notenoughinfo
Submitted twice: https://bugs.php.net/fix.php?id=75496&r=submittedtwice
register_globals: https://bugs.php.net/fix.php?id=75496&r=globals
PHP 4 support discontinued: https://bugs.php.net/fix.php?id=75496&r=php4
Daylight Savings: https://bugs.php.net/fix.php?id=75496&r=dst
IIS Stability: https://bugs.php.net/fix.php?id=75496&r=isapi
Install GNU Sed: https://bugs.php.net/fix.php?id=75496&r=gnused
Floating point limitations: https://bugs.php.net/fix.php?id=75496&r=float
No Zend Extensions: https://bugs.php.net/fix.php?id=75496&r=nozend
MySQL Configuration Error: https://bugs.php.net/fix.php?id=75496&r=mysqlcfg