📜 ⬆️ ⬇️

Protect gitlab and gitolite from password and key picking

Most recently, an attack began on my server with a git repository on the selection of passwords to gitlab and keys to ssh. The intentions of the intruders are clear - pull out the source code of the proprietary application stored in git.

I do not quite understand the attempts to select ssh-keys, because It’s problematic to choose an RSA key (it will take dozens of years), but I did make some restrictions so that the logs would not be so “dirty”.

Who cares how to protect gitolite and gitlab (works for nginx) from selecting passwords - welcome under cat.

Ssh protection


Many people know that Linux sshd by itself does not know how to limit the number of connections. For us, this was not a problem, we limited them to the firewall level.
')
In the standard iptables distribution under CentOS there is a hashlimit module. We will use it. I wrote the following rules for iptables:
iptables -N ssh_input iptables -A ssh_input \ -m hashlimit \ --hashlimit 5/m \ --hashlimit-burst 5 \ --hashlimit-mode srcip,dstport \ --hashlimit-name ssh \ --hashlimit-htable-expire 3600000 \ -j ACCEPT iptables -A ssh_input -p tcp -j REJECT --reject-with tcp-reset iptables -A INPUT -m state -m tcp -p tcp --dport 22 --state NEW -j ssh_input 

What did we do? First we added the ssh_input chain. Then we add a rule that limits the number of connections to 5 per minute (--hashlimit 5 / m --hashlimit-burst 5). In it we specify the parameters for which it is worthwhile to group connections (--hashlimit-mode srcip, dstport). After we add the rule that denies access (-j REJECT). And we add a chain to input with the conditions that the connections should be new and arrive at port 22.

How do these rules work? All packets with a new connection flag on port 22 are sent to the ssh_input chain for processing. There, under the condition that the number of such connections from this ip does not exceed 5 per minute, the transmission of a packet occurs (-j ACCEPT). If the conditions are not met go to the following rule: -j REJECT.

Now our attacker can for years (tens, hundreds of years?) Pick up the ssh key. And "zagazhivaniya" log will be smaller.

Gitlab protection


Also, attackers are trying to find a password to the gitlab web interface. As front-end we use Nginx. It is there rather old version 0.8.55 and it is not the time and desire to update it now.

First of all, we add basic authorization and limit the number of connections per minute (so that it would not be so easy to pick up this password). The problem of restriction in our case is such that loading a web page causes about 15 more calls to the server for statics. This will force us to allow more than 15 connections per second. This does not eliminate us. having 15 connections per second on each ip, an attacker will be able to pick up a password and we do the following with “ears”:

The login and password of the basic-authorization is common to all users and serves only as a hindrance to the selection of a password from the web application itself. If so, then we can do the following check:

 if ($http_authorization != "Basic secretdsddsaadsdsasad=="){ return 403; break; } 


for all urls other than /. In fact, we do basic authorization and a limit of 5 attempts per minute for 1 ip:

 limit_req_zone $binary_remote_addr zone=one:10m rate=5r/m; ... server { .... location = / { auth_basic "Top secret"; auth_basic_user_file /etc/nginx/conf.d/ssl/.htpasswd; limit_req zone=one burst=5 nodelay; ..... } .... } 


And now let's imagine that our basic password was still picked up or stolen. We also protect the application entry form:

 limit_req_zone $binary_remote_addr zone=two:10m rate=5r/m; ... server { ... location = /users/sign_in { if ($http_authorization != "Basic secretdsddsaadsdsasad=="){ //       basic  return 403; break; } limit_req zone=two burst=5 nodelay; .... } .... } 


And finally, the main lockishin for other addresses:

 server { ... location / { if ($http_authorization != "Basic secretdsddsaadsdsasad=="){ //       basic  return 403; break; } ... } } 


Thus, when requesting without basic-authorization on any url except the root, we get 403. Basic-authorization is possible only at the root and is limited to 5 requests per minute. Even if you select basic-authorization, the authorization form in the web application is limited to 5 requests per minute. I allocated restrictions on entry to the basic and web applications to different zones so that input errors of different passwords in different places would not accumulate and real users would not get "Service unavailable".

Source: https://habr.com/ru/post/146130/


All Articles