perf: 提升服务注册安全性

This commit is contained in:
ibuler 2025-03-27 16:07:57 +08:00 committed by Bryan
parent 9ed822bb3e
commit b55000663e
6 changed files with 52 additions and 9 deletions

View File

@ -0,0 +1,30 @@
import os
import requests
from httpsig.requests_auth import HTTPSignatureAuth
import datetime
def test_drf_ak():
KEY_ID = os.environ.get('KEY_ID') or ''
SECRET = os.environ.get('KEY_SECRET') or ''
signature_headers = ['(request-target)', 'date']
now = datetime.datetime.now()
headers = {
'Host': 'localhost:8000',
'Accept': 'application/json',
'Date': now.strftime('%a, %d %b %Y %H:%M:%S GMT'),
}
# url = 'http://localhost:8080/api/v1/assets/assets/?limit=100'
url = 'http://localhost:8080/api/v1/users/users/?limit=100'
auth = HTTPSignatureAuth(key_id=KEY_ID, secret=SECRET,
algorithm='hmac-sha256',
headers=signature_headers)
req = requests.get(url, auth=auth, headers=headers)
print(req.content)
if __name__ == '__main__':
test_drf_ak()

View File

@ -27,10 +27,23 @@ class IsServiceAccount(IsValidUser):
class WithBootstrapToken(permissions.BasePermission): class WithBootstrapToken(permissions.BasePermission):
def check_can_register(self):
enabled = settings.SECURITY_SERVICE_ACCOUNT_REGISTRATION
if enabled == 'auto':
return time.time() - settings.JUMPSERVER_UPTIME < 300
elif enabled:
return True
else:
return False
def has_permission(self, request, view): def has_permission(self, request, view):
authorization = request.META.get('HTTP_AUTHORIZATION', '') authorization = request.META.get('HTTP_AUTHORIZATION', '')
if not authorization: if not authorization:
return False return False
if not self.check_can_register():
return False
request_bootstrap_token = authorization.split()[-1] request_bootstrap_token = authorization.split()[-1]
return settings.BOOTSTRAP_TOKEN == request_bootstrap_token return settings.BOOTSTRAP_TOKEN == request_bootstrap_token

View File

@ -568,7 +568,7 @@ class Config(dict):
'SECURITY_COMMAND_BLACKLIST': [ 'SECURITY_COMMAND_BLACKLIST': [
'reboot', 'shutdown', 'poweroff', 'halt', 'dd', 'half', 'top' 'reboot', 'shutdown', 'poweroff', 'halt', 'dd', 'half', 'top'
], ],
'SECURITY_SERVICE_ACCOUNT_REGISTRATION': True, 'SECURITY_SERVICE_ACCOUNT_REGISTRATION': 'auto',
'SECURITY_VIEW_AUTH_NEED_MFA': True, 'SECURITY_VIEW_AUTH_NEED_MFA': True,
'SECURITY_MAX_IDLE_TIME': 30, 'SECURITY_MAX_IDLE_TIME': 30,
'SECURITY_MAX_SESSION_TIME': 24, 'SECURITY_MAX_SESSION_TIME': 24,

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
import os import os
import time
from .base import ( from .base import (
REDIS_SSL_CA, REDIS_SSL_CERT, REDIS_SSL_KEY, REDIS_SSL_REQUIRED, REDIS_USE_SSL, REDIS_SSL_CA, REDIS_SSL_CERT, REDIS_SSL_KEY, REDIS_SSL_REQUIRED, REDIS_USE_SSL,
REDIS_PROTOCOL, REDIS_SENTINEL_SERVICE_NAME, REDIS_SENTINELS, REDIS_SENTINEL_PASSWORD, REDIS_PROTOCOL, REDIS_SENTINEL_SERVICE_NAME, REDIS_SENTINELS, REDIS_SENTINEL_PASSWORD,
@ -197,3 +197,5 @@ PIICO_DEVICE_ENABLE = CONFIG.PIICO_DEVICE_ENABLE
PIICO_DRIVER_PATH = CONFIG.PIICO_DRIVER_PATH PIICO_DRIVER_PATH = CONFIG.PIICO_DRIVER_PATH
LEAK_PASSWORD_DB_PATH = CONFIG.LEAK_PASSWORD_DB_PATH LEAK_PASSWORD_DB_PATH = CONFIG.LEAK_PASSWORD_DB_PATH
JUMPSERVER_UPTIME = int(time.time())

View File

@ -18,7 +18,11 @@ class TerminalSettingSerializer(serializers.Serializer):
('25', '25'), ('25', '25'),
('50', '50'), ('50', '50'),
) )
SECURITY_SERVICE_ACCOUNT_REGISTRATION = serializers.BooleanField( SECURITY_SERVICE_ACCOUNT_REGISTRATION = serializers.ChoiceField(
choices=[
('auto', _('Auto(Enabled for the first 5 minutes after startup, then disabled.)')),
(True, _('Enable')), (False, _('Disable'))
],
required=True, label=_('Registration'), required=True, label=_('Registration'),
help_text=_( help_text=_(
"Allow component register, after all component setup, you should disable this for security" "Allow component register, after all component setup, you should disable this for security"

View File

@ -85,12 +85,6 @@ class TerminalRegistrationApi(generics.CreateAPIView):
permission_classes = [WithBootstrapToken] permission_classes = [WithBootstrapToken]
http_method_names = ['post'] http_method_names = ['post']
def create(self, request, *args, **kwargs):
if not settings.SECURITY_SERVICE_ACCOUNT_REGISTRATION:
data = {"error": "service account registration disabled"}
return Response(data=data, status=status.HTTP_400_BAD_REQUEST)
return super().create(request, *args, **kwargs)
class EncryptedTerminalConfig(generics.CreateAPIView): class EncryptedTerminalConfig(generics.CreateAPIView):
serializer_class = serializers.EncryptedConfigSerializer serializer_class = serializers.EncryptedConfigSerializer