Skip to content

Commit 423a05a

Browse files
committed
add automatic padding of the payload and ability to disable it for bandwidth
1 parent 3b32ed8 commit 423a05a

File tree

4 files changed

+109
-5
lines changed

4 files changed

+109
-5
lines changed

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,25 @@ $webPush = new WebPush($apiKeys);
8181
$webPush->sendNotification($endpoint, null, null, true);
8282
```
8383

84+
### Payload length and security
85+
As previously stated, payload will be encrypted by the library. The maximum payload length is 4078 bytes (or ASCII characters).
86+
87+
However, when you encrypt a string of a certain length, the resulting string will always have the same length,
88+
no matter how many times you encrypt the initial string. This can make attackers guess the content of the payload.
89+
In order to circumvent this, this library can add some null padding to the initial payload, so that all the input of the encryption process
90+
will have the same length. This way, all the output of the encryption process will also have the same length and attackers won't be able to
91+
guess the content of your payload. The downside of this approach is that you will use more bandwidth than if you didn't pad the string.
92+
That's why the library provides the option to disable this security measure:
93+
94+
```php
95+
<?php
96+
97+
use Minishlink\WebPush\WebPush;
98+
99+
$webPush = new WebPush();
100+
$webPush->setAutomaticPadding(false); // disable automatic padding
101+
```
102+
84103
### Time To Live
85104
Time To Live (TTL, in seconds) is how long a push message is retained by the push service (eg. Mozilla) in case the user browser
86105
is not yet accessible (eg. is not connected). You may want to use a very long time for important notifications. The default TTL is 4 weeks.

src/Encryption.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,17 @@
1818

1919
final class Encryption
2020
{
21+
const MAX_PAYLOAD_LENGTH = 4078;
22+
23+
/**
24+
* @param $payload
25+
* @return string
26+
*/
27+
public static function automaticPadding($payload)
28+
{
29+
return str_pad($payload, self::MAX_PAYLOAD_LENGTH, chr(0), STR_PAD_LEFT);
30+
}
31+
2132
/**
2233
* @param string $payload
2334
* @param string $userPublicKey MIME base 64 encoded

src/WebPush.php

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ class WebPush
3636
/** @var int Time To Live of notifications */
3737
private $TTL;
3838

39+
/** @var bool Automatic padding of payloads, if disabled, trade security for bandwidth */
40+
private $automaticPadding = true;
41+
3942
/** @var boolean */
4043
private $payloadEncryptionSupport;
4144

@@ -45,9 +48,9 @@ class WebPush
4548
/**
4649
* WebPush constructor.
4750
*
48-
* @param array $apiKeys Some servers needs authentication. Provide your API keys here. (eg. array('GCM' => 'GCM_API_KEY'))
49-
* @param int|null $TTL Time To Live of notifications, default being 4 weeks.
50-
* @param int|null $timeout Timeout of POST request
51+
* @param array $apiKeys Some servers needs authentication. Provide your API keys here. (eg. array('GCM' => 'GCM_API_KEY'))
52+
* @param int|null $TTL Time To Live of notifications, default being 4 weeks.
53+
* @param int|null $timeout Timeout of POST request
5154
* @param AbstractClient|null $client
5255
*/
5356
public function __construct(array $apiKeys = array(), $TTL = 2419200, $timeout = 30, AbstractClient $client = null)
@@ -82,8 +85,14 @@ public function sendNotification($endpoint, $payload = null, $userPublicKey = nu
8285
throw new \ErrorException('The API has changed: sendNotification now takes the optional user auth token as parameter.');
8386
}
8487

85-
if(isset($payload) && strlen($payload) > 4078) {
86-
throw new \ErrorException('Size of payload must not be greater than 4078 octets.');
88+
if(isset($payload)) {
89+
if (strlen($payload) > Encryption::MAX_PAYLOAD_LENGTH) {
90+
throw new \ErrorException('Size of payload must not be greater than '.Encryption::MAX_PAYLOAD_LENGTH.' octets.');
91+
}
92+
93+
if ($this->automaticPadding) {
94+
$payload = Encryption::automaticPadding($payload);
95+
}
8796
}
8897

8998
// sort notification by server type
@@ -298,10 +307,14 @@ public function getBrowser()
298307

299308
/**
300309
* @param Browser $browser
310+
*
311+
* @return WebPush
301312
*/
302313
public function setBrowser($browser)
303314
{
304315
$this->browser = $browser;
316+
317+
return $this;
305318
}
306319

307320
/**
@@ -314,9 +327,33 @@ public function getTTL()
314327

315328
/**
316329
* @param int $TTL
330+
*
331+
* @return WebPush
317332
*/
318333
public function setTTL($TTL)
319334
{
320335
$this->TTL = $TTL;
336+
337+
return $this;
338+
}
339+
340+
/**
341+
* @return boolean
342+
*/
343+
public function isAutomaticPadding()
344+
{
345+
return $this->automaticPadding;
346+
}
347+
348+
/**
349+
* @param boolean $automaticPadding
350+
*
351+
* @return WebPush
352+
*/
353+
public function setAutomaticPadding($automaticPadding)
354+
{
355+
$this->automaticPadding = $automaticPadding;
356+
357+
return $this;
321358
}
322359
}

tests/EncryptionTest.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the WebPush library.
5+
*
6+
* (c) Louis Lagrange <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
use Minishlink\WebPush\Encryption;
13+
14+
class EncryptionTest extends PHPUnit_Framework_TestCase
15+
{
16+
/**
17+
* @dataProvider payloadProvider
18+
*
19+
* @param string $payload
20+
*/
21+
public function testAutomaticPadding($payload)
22+
{
23+
$res = Encryption::automaticPadding($payload);
24+
25+
$this->assertContains('test', $res);
26+
$this->assertEquals(4078, strlen($res));
27+
}
28+
29+
public function payloadProvider()
30+
{
31+
return array(
32+
array('test'),
33+
array(str_repeat('test', 1019)),
34+
array(str_repeat('test', 1019).'te'),
35+
);
36+
}
37+
}

0 commit comments

Comments
 (0)