mirror of
https://github.com/jumpserver/jumpserver.git
synced 2025-09-16 07:18:22 +00:00
feat(terminal):危险命令告警功能
This commit is contained in:
@@ -1,25 +1,28 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
import time
|
||||
from django.conf import settings
|
||||
from django.utils import timezone
|
||||
from django.shortcuts import HttpResponse
|
||||
from rest_framework import viewsets
|
||||
from rest_framework import generics
|
||||
from rest_framework.fields import DateTimeField
|
||||
from rest_framework.response import Response
|
||||
from rest_framework import status
|
||||
from django.template import loader
|
||||
|
||||
|
||||
from orgs.utils import current_org
|
||||
from common.permissions import IsOrgAdminOrAppUser, IsOrgAuditor
|
||||
from common.permissions import IsOrgAdminOrAppUser, IsOrgAuditor, IsAppUser
|
||||
from common.utils import get_logger
|
||||
from terminal.utils import send_command_alert_mail
|
||||
from terminal.serializers import InsecureCommandAlertSerializer
|
||||
from ..backends import (
|
||||
get_command_storage, get_multi_command_storage,
|
||||
SessionCommandSerializer,
|
||||
)
|
||||
|
||||
logger = get_logger(__name__)
|
||||
__all__ = ['CommandViewSet', 'CommandExportApi']
|
||||
__all__ = ['CommandViewSet', 'CommandExportApi', 'InsecureCommandAlertAPI']
|
||||
|
||||
|
||||
class CommandQueryMixin:
|
||||
@@ -134,3 +137,19 @@ class CommandExportApi(CommandQueryMixin, generics.ListAPIView):
|
||||
filename = 'command-report-{}.html'.format(int(time.time()))
|
||||
response['Content-Disposition'] = 'attachment; filename="%s"' % filename
|
||||
return response
|
||||
|
||||
|
||||
class InsecureCommandAlertAPI(generics.CreateAPIView):
|
||||
permission_classes = [IsAppUser]
|
||||
serializer_class = InsecureCommandAlertSerializer
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
serializer = InsecureCommandAlertSerializer(data=request.data, many=True)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
commands = serializer.validated_data
|
||||
for command in commands:
|
||||
if command['risk_level'] >= settings.SECURITY_INSECURE_COMMAND_LEVEL and \
|
||||
settings.SECURITY_INSECURE_COMMAND and \
|
||||
settings.SECURITY_INSECURE_COMMAND_EMAIL_RECEIVER:
|
||||
send_command_alert_mail(command)
|
||||
return Response()
|
||||
|
@@ -27,6 +27,11 @@ class AbstractSessionCommand(OrgModelMixin):
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
@classmethod
|
||||
def get_risk_level_str(cls, risk_level):
|
||||
risk_mapper = dict(cls.RISK_LEVEL_CHOICES)
|
||||
return risk_mapper.get(risk_level)
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, d):
|
||||
self = cls()
|
||||
|
@@ -24,3 +24,11 @@ class SessionCommandSerializer(serializers.Serializer):
|
||||
def get_risk_level_display(obj):
|
||||
risk_mapper = dict(AbstractSessionCommand.RISK_LEVEL_CHOICES)
|
||||
return risk_mapper.get(obj.risk_level)
|
||||
|
||||
|
||||
class InsecureCommandAlertSerializer(serializers.Serializer):
|
||||
input = serializers.CharField()
|
||||
asset = serializers.CharField()
|
||||
user = serializers.CharField()
|
||||
risk_level = serializers.IntegerField()
|
||||
session = serializers.UUIDField()
|
||||
|
@@ -12,6 +12,7 @@ from django.conf import settings
|
||||
from django.core.files.storage import default_storage
|
||||
from django.core.cache import cache
|
||||
|
||||
from assets.models import Asset
|
||||
from users.models import User
|
||||
from orgs.mixins.models import OrgModelMixin
|
||||
from common.mixins import CommonModelMixin
|
||||
@@ -227,6 +228,10 @@ class Session(OrgModelMixin):
|
||||
local_path = rel_path
|
||||
return local_path
|
||||
|
||||
@property
|
||||
def asset_obj(self):
|
||||
return Asset.objects.get(id=self.asset_id)
|
||||
|
||||
@property
|
||||
def _date_start_first_has_replay_rdp_session(self):
|
||||
if self.__class__._DATE_START_FIRST_HAS_REPLAY_RDP_SESSION is None:
|
||||
|
@@ -3,3 +3,4 @@
|
||||
from .terminal import *
|
||||
from .session import *
|
||||
from .storage import *
|
||||
from .command import *
|
||||
|
10
apps/terminal/serializers/command.py
Normal file
10
apps/terminal/serializers/command.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# ~*~ coding: utf-8 ~*~
|
||||
from rest_framework import serializers
|
||||
|
||||
|
||||
class InsecureCommandAlertSerializer(serializers.Serializer):
|
||||
input = serializers.CharField()
|
||||
asset = serializers.CharField()
|
||||
user = serializers.CharField()
|
||||
risk_level = serializers.IntegerField()
|
||||
session = serializers.UUIDField()
|
@@ -31,6 +31,7 @@ urlpatterns = [
|
||||
name='terminal-access-key'),
|
||||
path('terminals/config/', api.TerminalConfig.as_view(), name='terminal-config'),
|
||||
path('commands/export/', api.CommandExportApi.as_view(), name="command-export"),
|
||||
path('commands/insecure-command/', api.InsecureCommandAlertAPI.as_view(), name="command-alert"),
|
||||
path('replay-storages/<uuid:pk>/test-connective/', api.ReplayStorageTestConnectiveApi.as_view(), name='replay-storage-test-connective'),
|
||||
path('command-storages/<uuid:pk>/test-connective/', api.CommandStorageTestConnectiveApi.as_view(), name='command-storage-test-connective')
|
||||
# v2: get session's replay
|
||||
|
@@ -4,12 +4,15 @@ import os
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.files.storage import default_storage
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
import jms_storage
|
||||
|
||||
from common.utils import get_logger
|
||||
from common.tasks import send_mail_async
|
||||
from common.utils import get_logger, reverse
|
||||
from settings.models import Setting
|
||||
|
||||
from .backends import server_replay_storage
|
||||
from .models import ReplayStorage
|
||||
from .models import ReplayStorage, Session, Command
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
@@ -63,3 +66,38 @@ def get_session_replay_url(session):
|
||||
if local_path is None:
|
||||
local_path, url = download_session_replay(session)
|
||||
return local_path, url
|
||||
|
||||
|
||||
def send_command_alert_mail(command):
|
||||
session_obj = Session.objects.get(id=command['session'])
|
||||
subject = _("Insecure Command Alert: [%(name)s->%(login_from)s@%(remote_addr)s] $%(command)s") % {
|
||||
'name': command['user'],
|
||||
'login_from': session_obj.get_login_from_display(),
|
||||
'remote_addr': session_obj.remote_addr,
|
||||
'command': command['input']
|
||||
}
|
||||
recipient_list = settings.SECURITY_INSECURE_COMMAND_EMAIL_RECEIVER.split(',')
|
||||
message = _("""
|
||||
Command: %(command)s
|
||||
<br>
|
||||
Asset: %(host_name)s (%(host_ip)s)
|
||||
<br>
|
||||
User: %(user)s
|
||||
<br>
|
||||
Level: %(risk_level)s
|
||||
<br>
|
||||
Session: <a href="%(session_detail_url)s">session detail</a>
|
||||
<br>
|
||||
""") % {
|
||||
'command': command['input'],
|
||||
'host_name': command['asset'],
|
||||
'host_ip': session_obj.asset_obj.ip,
|
||||
'user': command['user'],
|
||||
'risk_level': Command.get_risk_level_str(command['risk_level']),
|
||||
'session_detail_url': reverse('api-terminal:session-detail',
|
||||
kwargs={'pk': command['session']},
|
||||
external=True, api_to_ui=True),
|
||||
}
|
||||
logger.debug(message)
|
||||
|
||||
send_mail_async.delay(subject, message, recipient_list, html_message=message)
|
||||
|
Reference in New Issue
Block a user