У сервера apache
есть возможность сделать базовую авторизацию. Чтобы закрыть директорию, в неё нужно поместить два файла – .htaccess
и .htpasswd
.
# .htaccess
AuthType Basic
AuthName "Authorization"
AuthUserFile /путь_до_директории/.htpasswd
Require valid-user
AuthName "Authorization"
– сообщение в окне ввода логина и пароля, кириллица не поддерживается, в Google Chrome вообще не выводится.
AuthUserFile /путь_до_директории/.htpasswd
– путь до файла с паролями.
Авторизацией можно закрыть только определенные файлы, например ZIP-архивы
.
# .htaccess
<Files arhive.zip>
AuthType Basic
AuthName "Authorization"
AuthUserFile /путь_до_директории/.htpasswd
Require valid-user
</Files>
На некоторых хостингах авторизация на статические файлы (изображения, шрифты и т.д.) может не работать т.к. они отдаются через Nginx
.
Стоит проверить прямой доступ к самим файлам .htaccess
и .htpasswd
из браузера, если да, то закрыть его:
# .htaccess
<FilesMatch ".(htaccess|htpasswd)$">
Order Allow,Deny
Deny from all
</FilesMatch>
В файле хранится пары логина и хеша пароля, например:
admin:$apr1$TCrF2kqA$TSMYziwt.qCkrct9yx4vv1
Логин может содержать латинские буквы, цифры, - и _, регистрозависимый.
htpasswd -m .htpasswd user
В настоящее время считается очень безопасным, работает начиная с версии 2.4, формат:
$2y$
или $2a$
+ результат алгоритма crypt_blowfish
.
<?php
function bcrypt($password)
{
$rounds = 12;
$salt = sprintf('$2a$%02d$', $rounds) . substr(str_replace('+', '.', base64_encode(pack('N4', mt_rand(), mt_rand(), mt_rand(), mt_rand()))), 0, 22);
return crypt($password, $salt);
}
echo bcrypt('123456'); // $2a$12$dMHIiiPfeSMxqj3/Wt1.z.Mo7NPza1x/WANl7hDXZJzxxKKorz5um
Специфический алгоритм Apache
(1000 итераций MD5
случайной соли и пароля), работает во всех версиях.
$apr1$
+ результат алгоритма.
<?php
function crypt_apr1_md5($password)
{
$salt = substr(str_shuffle('abcdefghijklmnopqrstuvwxyz0123456789'), 0, 8);
$len = strlen($password);
$text = $password . '$apr1$' . $salt;
$bin = pack('H32', md5($password . $salt . $password));
for($i = $len; $i > 0; $i -= 16) {
$text .= substr($bin, 0, min(16, $i));
}
for($i = $len; $i > 0; $i >>= 1) {
$text .= ($i & 1) ? chr(0) : $password{0};
}
$bin = pack('H32', md5($text));
for($i = 0; $i < 1000; $i++) {
$new = ($i & 1) ? $password : $bin;
if ($i % 3) {
$new .= $salt;
}
if ($i % 7) {
$new .= $password;
}
$new .= ($i & 1) ? $bin : $password;
$bin = pack('H32', md5($new));
}
$tmp = '';
for ($i = 0; $i < 5; $i++) {
$k = $i + 6;
$j = $i + 12;
if ($j == 16) $j = 5;
$tmp = $bin[$i] . $bin[$k] . $bin[$j] . $tmp;
}
$tmp = chr(0) . chr(0) . $bin[11] . $tmp;
$tmp = strtr(
strrev(substr(base64_encode($tmp), 2)),
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
'./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
);
return '$apr1$' . $salt . '$' . $tmp;
}
echo crypt_apr1_md5('123456'); // $apr1$h9j4azoy$unmKNqjZlRfZv5xRetm9p1
Работает только на Unix
хостингах и до версии Apache 2.2.17
. Ограничивает длину пароля до 8 символов. Считается небезопасным.
<?php
function crypt3($password)
{
return crypt($password, substr($password, 0, 2));
}
echo crypt3('123456'); // 12tir.zIbWQ3c
PHP
SHA-1
Этот алгоритм небезопасен по современным стандартам, работает во всех версиях.
{SHA} + результат SHA-1 (бинарная строка из 20-ти символов) закодированный в Base64.
function hash_sha1($password)
{
return '{SHA}' . base64_encode(sha1($password, true));
}
echo hash_sha1('123456'); // {SHA}fEqNCco3Yq9h5ZUglD3CZJT4lBs=
Реквизиты доступа к закрытой директории можно передать в URL:
https://логин:пароль@example.com/path
Если такие URL
использовать в src
изображений, скриптов и стилей, то работать они не будут, вызвав ошибку:
Subresource requests whose URLs contain embedded credentials (e.g. `https://user:pass@host/`) are blocked.
Завершение сеанса происходит по закрытию браузера, но не вкладки.
document.execCommand("ClearAuthenticationCache");
A "basic" way
var p = window.location.protocol + '//'
// current location must return 200 OK for this GET
window.location = window.location.href.replace(p, p + 'logout:password@')
An "asynchronous" way of doing the above is to do an AJAX call utilizing the logout username.
Example:
(function(safeLocation){
var outcome, u, m = "You should be logged out now.";
// IE has a simple solution for it - API:
try { outcome = document.execCommand("ClearAuthenticationCache") }catch(e){}
// Other browsers need a larger solution - AJAX call with special user name - 'logout'.
if (!outcome) {
// Let's create an xmlhttp object
outcome = (function(x){
if (x) {
// the reason we use "random" value for password is
// that browsers cache requests. changing
// password effectively behaves like cache-busing.
x.open("HEAD", safeLocation || location.href, true, "logout", (new Date()).getTime().toString())
x.send("")
// x.abort()
return 1 // this is **speculative** "We are done."
} else {
return
}
})(window.XMLHttpRequest ? new window.XMLHttpRequest() : ( window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : u ))
}
if (!outcome) {
m = "Your browser is too old or too weird to support log out functionality. Close all windows and restart the browser."
}
alert(m)
// return !!outcome
})(/*if present URI does not return 200 OK for GET, set some other 200 OK location here*/)
Other way
function logout(secUrl, redirUrl) {
if (bowser.msie) {
document.execCommand('ClearAuthenticationCache', 'false');
} else if (bowser.gecko) {
$.ajax({
async: false,
url: secUrl,
type: 'GET',
username: 'logout'
});
} else if (bowser.webkit) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", secUrl, true);
xmlhttp.setRequestHeader("Authorization", "Basic logout");
xmlhttp.send();
} else {
alert("Logging out automatically is unsupported for " + bowser.name
+ "\nYou must close the browser to log out.");
}
setTimeout(function () {
window.location.href = redirUrl;
}, 200);
}