{"id":24669099,"url":"https://github.com/solution10/heat","last_synced_at":"2025-03-21T13:26:00.130Z","repository":{"id":57055395,"uuid":"80307864","full_name":"solution10/heat","owner":"solution10","description":"Brute force protection library.","archived":false,"fork":false,"pushed_at":"2017-02-04T17:11:43.000Z","size":20,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-26T09:19:29.126Z","etag":null,"topics":["brute-force","composer-packages","php","security"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/solution10.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-01-28T20:13:16.000Z","updated_at":"2022-12-12T12:40:24.000Z","dependencies_parsed_at":"2022-08-24T14:00:31.133Z","dependency_job_id":null,"html_url":"https://github.com/solution10/heat","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solution10%2Fheat","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solution10%2Fheat/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solution10%2Fheat/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solution10%2Fheat/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/solution10","download_url":"https://codeload.github.com/solution10/heat/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244804903,"owners_count":20513191,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["brute-force","composer-packages","php","security"],"created_at":"2025-01-26T09:19:31.320Z","updated_at":"2025-03-21T13:26:00.094Z","avatar_url":"https://github.com/solution10.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Solution10\\Heat\n\nA simple library for tracking bad behaviour of given users (usually identified by their IP) and locking\nthem out when they dun goofed too much. Usual uses include preventing brute-force and dictionary attacks\nagainst your login endpoints.\n\n[![Build Status](https://travis-ci.org/Solution10/heat.svg?branch=master)](https://travis-ci.org/Solution10/heat)\n[![Latest Stable Version](https://poser.pugx.org/solution10/heat/v/stable.svg)](https://packagist.org/packages/solution10/heat)\n[![Total Downloads](https://poser.pugx.org/solution10/heat/downloads.svg)](https://packagist.org/packages/solution10/heat)\n[![License](https://poser.pugx.org/solution10/heat/license.svg)](https://packagist.org/packages/solution10/heat)\n\n- [Theory](#theory)\n- [Usage](#usage)\n    - [Creating Instances](#creating-instances)\n    - [Tracking Heat](#tracking-heat)\n    - [States](#states)\n    - [Lifetime](#lifetime)\n    - [Additional Methods](#additional-methods)\n    - [Silex Service Provider](#silex-service-provider)\n- [PHP Requirements](#php-requirements)\n- [Author](#author)\n- [License](#license)\n\n## Theory\n\nUsers can make mistakes, but those mistakes can also be a signal of an attack. Consider a login form; users\nmake mistakes entering their passwords and such, but after a few attempts, it could be someone attempting to\nbrute force their way into the system by guessing passwords.\n\nThis library provides a way of tracking \"heat\" - every time a user does something suspicious, their heat rating\nincreases until they are required to provide some other action to ensure they are genuine, such as solving a\nCAPTCHA. This heat accumulates as they perform actions and will be stored for a given time.\n\nThis library provides a simple tracking mechanism only, as well as a Silex service provider to help hook into\nthat framework.\n\n## Usage\n\nThe lib is pretty simple to use:\n\n### Creating Instances\n\n```php\n$c = new Doctrine\\Common\\Cache\\RedisCache();\n$h = new Solution10\\Heat\\Heat($_SERVER['REMOTE_ADDR'], $c);\n```\n\nYou need to provide an identifier for the user as well as a `Doctrine\\Common\\Cache\\Cache` instance to serve as the\nstorage backend.\n\nIn the above example we're using `$_SERVER['REMOTE_ADDR']` but this is a **bad idea**. Make use of something like\n`Symfony\\Component\\HttpFoundation\\Request::getClientIp()` instead that takes proxies and the like into account.\n\n### Tracking Heat\n\n```php\n$c = new Doctrine\\Common\\Cache\\RedisCache();\n$h = new Solution10\\Heat\\Heat($_SERVER['REMOTE_ADDR'], $c);\n\nif ($user-\u003egotTheirPasswordWrong()) {\n    $h-\u003eincrease(25);\n}\n\nif ($user-\u003esolvedCAPCTHA()) {\n    $h-\u003edecrease(50);\n}\n```\n\nYou can increase and decrease the heat of the current identifier using the `increase()` and `decrease()` methods.\n\nIf the user does something really good, or really terrible, you can use `increaseToMaximum()` and `decreaseToMinimum()`\nto immediately increase/decrease the users heat. **You should do this in extreme cases only**.\n\nDo **not** reset the users heat simply because they logged in. If you do, an attacker simply needs to log in with\ntheir own account every so often to reset the heat! Allow the lifetime to do it's job.\n\nYou can adjust the maximum and minimum temperatures using `setMaxTemperature()` and `setMinimumTemperature()`, the\ndefaults of which are 100 and 0 respectively.\n\nYou can read the heat at any time using `$h-\u003egetTemperature()`.\n\n### States\n\nAn identifier can be in one of three states; `SAFE`, `WARNING` and `CRITICAL`.\n\n**SAFE**: the user hasn't done enough to arouse suspicion yet. Consider them alright, for now.\n\n**WARNING**: the user has performed enough actions to be \u003e= 60% of maximum temperature. Probably time to throw\nthem a CAPTCHA to check they're legit.\n\n**CRITICAL**: the user has reached maximum temperature and should be considered dangerous. Block their ability to\nlog in for a while.\n\nYou can check the state with the following:\n\n```php\n// Boolean checks;\n$h-\u003eisSafe();\n$h-\u003eisWarning();\n$h-\u003eisCritical();\n\n// Checking state against constants;\n$h-\u003egetState() === Heat::SAFE;\n$h-\u003egetState() === Heat::WARNING;\n$h-\u003egetState() === Heat::CRITICAL;\n```\n\nYou can adjust the threshold between SAFE and CRITICAL using `$h-\u003esetSafeThreshold(0.4)`. This value is a float\nrepresenting the percentage of the maximum temperature, so setting a value of 0.4 is 40% of maximum.\n\n### Lifetime\n\nThe temperature is written into the Cache instance using `write()` which will only update the value if it changed\nfrom load. This is important, since it means that heat accumulates and stays for the lifetime that you define in\nthe class and can stick around for much longer.\n\nConsider - a user attempts three logins, raising their temperature to 60%. They then do nothing for three minutes, or\nlog in correctly, and then attempt another brute force. The previous three attempts remain, and the new one, bringing\nthe user to 80% heat means that the user stays at 80% for a further five minutes.\n\nThe default lifetime is 300 seconds or five minutes.\n\nYou can get and set the lifetime using:\n\n```php\n$h-\u003egetLifetime();\n$h-\u003esetLifetime(3600);\n```\n\n### Additional Methods\n\nEverything you would expect has getters and setters.\n\n```php\n$h-\u003egetIdentifier();\n$h-\u003esetIdentifier(string $identifier);\n\n$h-\u003egetStorage();\n$h-\u003esetStorage(Cache $storage);\n\n$h-\u003egetStoragePrefix();\n$h-\u003esetStoragePrefix(string $storagePrefix);\n\n$h-\u003egetMaxTemperature();\n$h-\u003esetMaxTemperature(int $maxTemperature);\n\n$h-\u003egetMinTemperature();\n$h-\u003esetMinTemperature(int $minTemperature);\n\n$h-\u003egetSafeThreshold();\n$h-\u003esetSafeThreshold(float $safeThreshold);\n\n$h-\u003egetLifetime();\n$h-\u003esetLifetime(int $lifetime);\n```\n\n### Silex Service Provider\n\nThe library provides a Service Provider for the [Silex microframework](http://silex.sensiolabs.org) which makes\nintegration easy.\n\nRegister the provider as normal:\n\n```php\n$app = new Silex\\Application();\n$app-\u003eregister(new \\Solution10\\Heat\\HeatTrackerServiceProvider(), [\n    's10.heat.storage' =\u003e new RedisCache() // replace as appropriate\n]);\n```\n\nThis provider gives you an instance of `Solution10\\Heat\\Heat` in the `$app['s10.heat']` DI path and binds onto the\n`$app-\u003ebefore()` and `$app-\u003efinished()` methods to provide the identifier from the IP address and the `write()`\nmethod call.\n\nThe `s10.heat.storage` parameter can be passed to `register()` to use your own cache provider, if you don't provide\none it'll use `ArrayCache` which is totally useless since it doesn't persist!\n\n## PHP Requirements\n\n- PHP \u003e= 7.0\n\n## Author\n\nAlex Gisby: [GitHub](http://github.com/alexgisby), [Twitter](http://twitter.com/alexgisby)\n\n## License\n\n[MIT](http://github.com/solution10/heat/tree/master/LICENSE.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsolution10%2Fheat","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsolution10%2Fheat","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsolution10%2Fheat/lists"}