mirror of https://github.com/jumpserver/jumpserver
				
				
				
			fix: Operatelog plaintext storage AKSK (#13506)
* fix: Operatelog plaintext storage AKSK * perf: Encrypt some field when saving operatelog * fix: Operatelog plaintext storage AKSK --------- Co-authored-by: jiangweidong <1053570670@qq.com>pull/13661/head
							parent
							
								
									d14d8869ac
								
							
						
					
					
						commit
						ba8d3be9a6
					
				| 
						 | 
				
			
			@ -5,7 +5,7 @@ from django.core.cache import cache
 | 
			
		|||
from django.db import transaction
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
 | 
			
		||||
from common.local import encrypted_field_set
 | 
			
		||||
from common.local import similar_encrypted_pattern, exclude_encrypted_fields
 | 
			
		||||
from common.utils import get_request_ip, get_logger
 | 
			
		||||
from common.utils.encode import Singleton
 | 
			
		||||
from common.utils.timezone import as_current_tz
 | 
			
		||||
| 
						 | 
				
			
			@ -109,19 +109,29 @@ class OperatorLogHandler(metaclass=Singleton):
 | 
			
		|||
            return ','.join(value)
 | 
			
		||||
        return json.dumps(value)
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def __similar_check(key):
 | 
			
		||||
        if not key or key in exclude_encrypted_fields:
 | 
			
		||||
            return False
 | 
			
		||||
 | 
			
		||||
        return bool(similar_encrypted_pattern.search(key))
 | 
			
		||||
 | 
			
		||||
    def __data_processing(self, dict_item, loop=True):
 | 
			
		||||
        encrypt_value = '******'
 | 
			
		||||
        for key, value in dict_item.items():
 | 
			
		||||
        new_data = {}
 | 
			
		||||
        for label, item in dict_item.items():
 | 
			
		||||
            value = item.get('value', '')
 | 
			
		||||
            field_name = item.get('name', '')
 | 
			
		||||
            if isinstance(value, bool):
 | 
			
		||||
                value = _('Yes') if value else _('No')
 | 
			
		||||
            elif isinstance(value, (list, tuple)):
 | 
			
		||||
                value = self.serialized_value(value)
 | 
			
		||||
            elif isinstance(value, dict) and loop:
 | 
			
		||||
                self.__data_processing(value, loop=False)
 | 
			
		||||
            if key in encrypted_field_set:
 | 
			
		||||
            if self.__similar_check(field_name):
 | 
			
		||||
                value = encrypt_value
 | 
			
		||||
            dict_item[key] = value
 | 
			
		||||
        return dict_item
 | 
			
		||||
            new_data[label] = value
 | 
			
		||||
        return new_data
 | 
			
		||||
 | 
			
		||||
    def data_processing(self, before, after):
 | 
			
		||||
        if before:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -82,7 +82,9 @@ def _get_instance_field_value(
 | 
			
		|||
            elif isinstance(f, GenericForeignKey):
 | 
			
		||||
                continue
 | 
			
		||||
            try:
 | 
			
		||||
                data.setdefault(str(f.verbose_name), value)
 | 
			
		||||
                data.setdefault(
 | 
			
		||||
                    str(f.verbose_name), {'name': getattr(f, 'column', ''), 'value': value}
 | 
			
		||||
                )
 | 
			
		||||
            except Exception as e:
 | 
			
		||||
                print(f.__dict__)
 | 
			
		||||
                raise e
 | 
			
		||||
| 
						 | 
				
			
			@ -106,7 +108,9 @@ def model_to_dict_for_operate_log(
 | 
			
		|||
            return
 | 
			
		||||
        try:
 | 
			
		||||
            field_key = getattr(f, 'verbose_name', None) or f.related_model._meta.verbose_name
 | 
			
		||||
            data.setdefault(str(field_key), value)
 | 
			
		||||
            data.setdefault(
 | 
			
		||||
                str(field_key), {'name': getattr(f, 'column', ''), 'value': value}
 | 
			
		||||
            )
 | 
			
		||||
        except:
 | 
			
		||||
            pass
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,6 @@ from django.db.models import Q, Manager, QuerySet
 | 
			
		|||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
from rest_framework.utils.encoders import JSONEncoder
 | 
			
		||||
 | 
			
		||||
from common.local import add_encrypted_field_set
 | 
			
		||||
from common.utils import contains_ip
 | 
			
		||||
from .utils import Encryptor
 | 
			
		||||
from .validators import PortRangeValidator
 | 
			
		||||
| 
						 | 
				
			
			@ -168,7 +167,6 @@ class EncryptTextField(EncryptMixin, models.TextField):
 | 
			
		|||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        add_encrypted_field_set(self.verbose_name)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class EncryptCharField(EncryptMixin, models.CharField):
 | 
			
		||||
| 
						 | 
				
			
			@ -184,7 +182,6 @@ class EncryptCharField(EncryptMixin, models.CharField):
 | 
			
		|||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        self.change_max_length(kwargs)
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        add_encrypted_field_set(self.verbose_name)
 | 
			
		||||
 | 
			
		||||
    def deconstruct(self):
 | 
			
		||||
        name, path, args, kwargs = super().deconstruct()
 | 
			
		||||
| 
						 | 
				
			
			@ -198,13 +195,11 @@ class EncryptCharField(EncryptMixin, models.CharField):
 | 
			
		|||
class EncryptJsonDictTextField(EncryptMixin, JsonDictTextField):
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        add_encrypted_field_set(self.verbose_name)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class EncryptJsonDictCharField(EncryptMixin, JsonDictCharField):
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        add_encrypted_field_set(self.verbose_name)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class PortField(models.IntegerField):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,18 +1,14 @@
 | 
			
		|||
from werkzeug.local import Local
 | 
			
		||||
import re
 | 
			
		||||
 | 
			
		||||
from django.utils import translation
 | 
			
		||||
from werkzeug.local import Local
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
thread_local = Local()
 | 
			
		||||
encrypted_field_set = {'password', 'secret'}
 | 
			
		||||
exclude_encrypted_fields = ('secret_type', 'secret_strategy', 'password_rules')
 | 
			
		||||
similar_encrypted_pattern = re.compile(
 | 
			
		||||
    'password|secret|token|passphrase|private|key|cert', re.IGNORECASE
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _find(attr):
 | 
			
		||||
    return getattr(thread_local, attr, None)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def add_encrypted_field_set(label):
 | 
			
		||||
    return
 | 
			
		||||
    if label:
 | 
			
		||||
        with translation.override('en'):
 | 
			
		||||
            encrypted_field_set.add(str(label))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,6 @@ from rest_framework import serializers
 | 
			
		|||
from rest_framework.fields import ChoiceField, empty
 | 
			
		||||
 | 
			
		||||
from common.db.fields import TreeChoices, JSONManyToManyField as ModelJSONManyToManyField
 | 
			
		||||
from common.local import add_encrypted_field_set
 | 
			
		||||
from common.utils import decrypt_password
 | 
			
		||||
 | 
			
		||||
__all__ = [
 | 
			
		||||
| 
						 | 
				
			
			@ -47,9 +46,7 @@ class EncryptedField(serializers.CharField):
 | 
			
		|||
        if write_only is None:
 | 
			
		||||
            write_only = True
 | 
			
		||||
        kwargs["write_only"] = write_only
 | 
			
		||||
        encrypted_key = kwargs.pop('encrypted_key', None)
 | 
			
		||||
        super().__init__(**kwargs)
 | 
			
		||||
        add_encrypted_field_set(encrypted_key or self.label)
 | 
			
		||||
 | 
			
		||||
    def to_internal_value(self, value):
 | 
			
		||||
        value = super().to_internal_value(value)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue