programing

데이터베이스의 자격 증명을 어디에 보관해야 합니까?

linuxpc 2023. 9. 3. 12:12
반응형

데이터베이스의 자격 증명을 어디에 보관해야 합니까?

데이터베이스의 사용자 이름과 암호를 xml 파일에 보관하고 스프링 보안의 보안 파일로 가져오는 것이 좋은 생각입니까? 더 좋은 옵션이 있습니까?암호를 암호화해야 하는 경우 phpMyAdmin에서 암호화된 버전의 암호를 찾는 방법은 무엇입니까?MySQL

login-service.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">

   <bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">

    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://localhost/muDB" />
    <property name="username" value="jack" />
    <property name="password" value="alex123432" />
   </bean>

</beans>

myproject-security.xml

      ....
    <beans:import resource='login-service.xml'/> 
      ....

참고: 모든 사용자 관련 암호가 이미 암호화되어 있으므로 테이블 열이 아닌 데이터베이스 자체의 암호를 숨길 뿐입니다.이 암호는 응용프로그램에서 데이터베이스에 연결하는 데 사용됩니다.

먼저, 공격자가 서버 파일에 액세스할 수 있는 권한을 얻으면 사용자가 암호를 도용할 수 있다는 점을(를) 알아야 합니다.

앱 서버의 데이터 소스를 사용하는 경우 일반 텍스트 암호의 위치를 다른 파일로 이동하기만 하면 됩니다.

일반 텍스트 암호를 저장하지 않기 위해 어떤 형태로든 암호화를 사용하는 경우에도 앱은 이미 가지고 있는 다른 암호로 암호를 해독해야 합니다.공격자가 시스템에 액세스하기 위해 최선을 다하면 공격자도 이를 알게 될 것이라는 확신을 가질 수 있습니다.당신이 하고 있는 일은 실제로 보안을 확보하기보다는 난독화(그리고 잘못된 안전감을 얻는 것)하는 것입니다.

보다 안전한 솔루션은 앱을 시작하는 동안 사용자가 암호(또는 DB 암호 해독을 위한 암호)를 제공하는 것이지만, 이는 관리를 매우 어렵게 만듭니다.또한 이미 누군가가 서버에 액세스할 수 있는 편집증(미친 보안 유형이 아닌 양호한 보안 유형)이 있는 경우에는 DB 암호가 시스템 메모리에 상주한다는 점을 고려해야 합니다.

그 외에는 비밀번호를 환경설정 파일에 보관하고(서버가 외부에 표시되지 않을 것이라는 확신을 가질 수 있음), 시스템을 잠그고 데이터베이스 사용자에게 필요한 최소 권한만 부여합니다.

한 가지 옵션은 일반 속성 파일에 사용자 이름/암호를 암호화된 형식으로 속성으로 저장할 수 있도록 Jasypt를 Spring 통합과 함께 사용하는 것입니다.자스립은 암호 해독을 투명하게 처리할 것입니다.

구성에 비밀번호가 있다는 것은 정말 최악이고 그것을 위한 은색 총알은 없습니다.그러나 이 솔루션은 대부분의 보안 bla-bla-bla를 준수합니다.또한 SCM의 자격 증명을 난독화합니다.

속성 자리 표시자 구성자:

import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.KeySpec;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;

public class EncryptedPropertyPlacementConfigurer extends PropertyPlaceholderConfigurer
{
    /** algorithm used for encrpytion and decryption */
    private static final String ALGORITHM = "PBEWithMD5AndDES";

    /** 8-byte Salt. */
    private static final byte[] SALT = { ... };

    /** Iteration count. */
    private static final int ITERATION_COUNT = 19;

    /** Stores parameter specification. */
    private static final AlgorithmParameterSpec PARAM_SPEC = new PBEParameterSpec(SALT, ITERATION_COUNT);

    //All properties starting with !! will be decrypted.
    private static final String ENCRYPTIGION_LEADIN = "!!";

    public static class EncrypterException extends RuntimeException
    {
        private static final long serialVersionUID = -7336009350594115318L;

        public EncrypterException(final String message, final Throwable cause)
        {
            super(message, cause);
        }

        public EncrypterException(final String message)
        {
            super(message);
        }
    }

    private static String decrypt(final String passPhrase, final String message)
    {
        // Create the key
        final KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), SALT, ITERATION_COUNT);
        SecretKey key;
        try
        {
            key = SecretKeyFactory.getInstance(ALGORITHM).generateSecret(keySpec);
        }
        catch (final Exception e)
        {
            throw new EncrypterException("Error setting up encryption details.", e);
        }

        if (!Base64.isBase64(message))
        {
            throw new EncrypterException("Message is not a valid base64 message.");
        }

        final String result;
        try
        {
            final Cipher cipher = Cipher.getInstance(ALGORITHM);

            cipher.init(Cipher.DECRYPT_MODE, key, PARAM_SPEC);

            final byte[] dec = Base64.decodeBase64(message);

            result = new String(cipher.doFinal(dec), "UTF-8");
        }
        catch (final Exception e)
        {
            throw new EncrypterException("Error decrypting content.", e);
        }

        return result;
    }

    @Override
    protected String convertPropertyValue(final String originalValue)
    {
        if (StringUtils.isNotBlank(originalValue) && originalValue.startsWith(ENCRYPTIGION_LEADIN))
        {
            return decrypt("<Your magic password>", originalValue.substring(2));
        }
        return super.convertPropertyValue(originalValue);
    }

}

당신의 콩:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">


    <bean id="propertyPlaceholderConfigurer" class="...EncryptedPropertyPlacementConfigurer ">
        <property name="location" value="classpath:/spring.properties" />
        <property name="ignoreResourceNotFound" value="true" />
    </bean>

   <bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">

    <property name="driverClassName" value="${jdbc.driver}" />
    <property name="url" value="${jdbc.url}" />
    <property name="username" value="${jdbc.user}" />
    <property name="password" value="${jdbc.password}" />
   </bean>
</beans>

속성 파일:

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost/muDB
jdbc.user=!!ar7CWlcL8eI=
jdbc.password=!!ar7CWlcL8eI=

참고: 무제한 JCE 정책을 사용하는 경우 더 나은 암호화 알고리즘을 사용할 수도 있지만, 우리는 난독화 이상을 수행하지 않기 때문에 이것은 속임수를 쓸 수 있고 디버깅 세션을 끝낼 수 없습니다.

업데이트:

이를 사용하여 암호를 생성할 수 있습니다.

import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.KeySpec;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;

import org.apache.commons.codec.binary.Base64;

public class Main
{

    private static class DesEncrypter
    {
        /** algorithm used for encrpytion and decryption */
        private static final String ALGORITHM = "PBEWithMD5AndDES";

        /** 8-byte Salt. */
        private static final byte[] SALT = { <You salt> };

        /** Iteration count. */
        private static final int ITERATION_COUNT = 19;

        /** Stores parameter specification. */
        private static final AlgorithmParameterSpec PARAM_SPEC = new PBEParameterSpec(
            SALT, ITERATION_COUNT);

        /** Key specification. */
        private final KeySpec keySpec;

        /** Secret key. */
        private final SecretKey key;

        public DesEncrypter(final String passPhrase)
        {
            // Create the key
            keySpec = new PBEKeySpec(passPhrase.toCharArray(), SALT, ITERATION_COUNT);
            try
            {
                key = SecretKeyFactory.getInstance(ALGORITHM).generateSecret(keySpec);
            }
            catch (final Exception ex)
            {
                throw new RuntimeException("Could not create DesEncrypter: " + ex.getMessage(), ex);
            }
        }

        public final String encrypt(final String message)
        {
            try
            {
                // Create cipher instance
                final Cipher cipher = Cipher.getInstance(ALGORITHM);
                // Initialize cipher
                cipher.init(Cipher.ENCRYPT_MODE, key, PARAM_SPEC);
                // Encode string
                final byte[] enc = cipher.doFinal(message.getBytes("UTF8"));
                // Encode bytes to base64 to get a string
                return Base64.encodeBase64String(enc);
            }
            catch (final Exception ex)
            {
                throw new RuntimeException("Error encrypting message.", ex);
            }
        }
    }

    public static void main(final String[] args)
    {
        if (args.length == 2)
        {
            System.out.println("!!" + new DesEncrypter(args[0]).encrypt(args[1]));
        }
    }
}

애플리케이션 서버에 보관하고 jndi 이름으로 받을 수 있습니다.

예를 들어 최대 절전 모드/이클립스 링크와 같은 jpa 구현을 사용하는 경우 다음과 같이 정의할 수 있습니다.

spring-security.xml

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="dataBase.db"/>
</bean>

persistence.xml

<persistence-unit name="dataBase.db" transaction-type="JTA">
...
    <jta-data-source>java:jboss/datasources/PostgresqlDS</jta-data-source>
...
</persistence-unit>

응용프로그램 서버에서 서버 구성 파일의 데이터베이스(데이터 원본)에 대한 연결을 정의해야 합니다.Jboss 7의 경우 stadalone.xml jboss 데이터 소스입니다.

좋은 오래된 닭과 달걀 문제.

데이터베이스의 사용자 이름과 비밀번호를 유지하는 것이 좋은 생각입니까? xml 파일을 스프링 보안의 보안 파일로 가져오시겠습니까?

소스 코드에 일반적으로 저장하는 것보다는 낫지만 SAP NetWeaver 또는 Oracle WebLogic과 같은 엔터프라이즈 애플리케이션 서버에서 이를 처리하는 것보다는 낫습니다.

좋은 점은 응용프로그램을 자격 증명과 분리하여 환경별 구성 및 OS 보안 제한을 허용한다는 것입니다.

대부분의 소프트웨어 솔루션과 마찬가지로 상황에 따라 다릅니다.그리고 당신의 경우, 그것은 그 목적을 위해 얼마나 "노력"을 바쳐야 하는지에 달려 있습니다.

더 좋은 방법이 없을까요?

파일에 자격 증명을 저장하는 경우에도 최소한 암호화하거나 암호화해야 합니다.그러나 다시 말하지만, 이것은 실제 암호를 "난독화"할 뿐입니다.

예를 들어, 동기화 알고리즘으로 암호화하려면 비밀 키가 필요합니다.그렇다면 이 비밀 열쇠는 어디에 보관될 것인가요?이것은 암호를 해킹하려는 노력을 더 크게 하지만 위험을 제거하지는 않는 순환 보안입니다.

제안 1: 자격 증명을 저장하는 파일을 OS 관리자와 시스템 사용자만 액세스할 수 있도록 하여 읽을 수 있도록 합니다.그 위에 비밀 키 암호화를 사용합니다.개인적으로 저는 항상 AES 256 알고리즘을 사용합니다.

제안 2: 파일에 저장하는 대신 인프라 팀(슈퍼 OS 관리자)에게 암호화된 암호를 시스템 매개 변수로 보내 달라고 요청합니다.자격 증명 보안 책임을 인프라 팀에 위임합니다.이것은 AWS Beanstalk와 RDS의 통합을 위한 현재 접근 방식입니다.

보안에 열광하는 경우:

  • 인프라 팀을 신뢰하지 않는 경우 애플리케이션 시작 시 사람이 수동으로 입력할 애플리케이션의 암호를 원할 수 있습니다.애플리케이션을 시작할 때 항상 사람이 있어야 하는 것과 같은 단점과 수평적 확장도 처리해야 합니다.

  • 운영 구성원이 서버에 삽입해야 하는 DVD 미디어 내에서 "물리적"으로 암호를 처리할 수 있습니다.또한 OS 내의 장치에 대한 액세스도 처리해야 합니다.

이해 관계자들에게 그것에 대해 말하는 것을 두려워하지 마세요.그/그들에게 "충분히" 받아들일 수 있는 것이 무엇인지 묻고 행복해 합니다.

자격 증명을 저장할 때는 항상 위험이 따릅니다.

암호를 암호화해야 하는 경우 암호화 방법 및 검색 방법 암호화된 버전의 phpMyAdmin?MySQL

암호를 복사하지 마십시오.서버 내부의 자격 증명을 처리해야 합니다.

한 가지 솔루션에서는 관리자만 X11 프로토콜 또는 콘솔을 통해 Java Crypt API를 기반으로 하는 맞춤형 소프트웨어에 액세스할 수 있도록 했습니다.이 소프트웨어는 안전한 방법으로 자격 증명을 변경하도록 설계되었습니다.

암호는 항상 안전한 SSH 연결(원격인 경우) 또는 로컬 액세스를 통해 전송되며, OS에서 권한이 그러한 방식으로 정의되었기 때문에 관리자와 서버 간에만 전송됩니다.

PphpMyAdmin의 경우 암호를 처리하는 고유한 방법이 있으며, 광범위한 사용자 지정 노력 없이는 두 솔루션을 하나로 통합할 수 없을 가능성이 높습니다.PphpMyAdmin 또는 다른 MySQL 클라이언트의 암호를 저장하지 마십시오. 보안 위험만 증가합니다.

속성 파일에 보관할 수 있습니다.

프로젝트에서 데이터베이스를 만들었습니다.STSIDE의 META-INF 아래 속성

Rails에서는 환경 변수의 중요한 데이터를 .env 파일에 보관하고 파일을 .gitignore에 추가합니다.저는 당신이 비슷한 것을 할 수 있을지 모르겠습니다.

"If I need to encrypt the password how to do it and how to find the encrypted version of password on phpMyAdmin"

다음과 같은 방법으로 암호화된 암호를 만들 수 있습니다.

http://bcrypthashgenerator.apphb.com/

..그러면 암호가 무엇인지 알게 되고 암호화된 버전을 phpMyadmin을 통해 올바른 테이블에 추가할 수 있습니다.

암호를 로컬 저장소에 보관하고 원격으로 배포하지 말아 주시겠습니까?Rails ENV와 유사한 시나리오를 설정할 수 있는지 궁금합니다.

다음과 같은 것을 본 적이 있습니까: http://www.jasypt.org/spring3.html

다른 사용자가 언급했듯이 서버에 암호를 저장하는 경우 공격자가 컴퓨터에 액세스할 수 있는 권한을 얻으면 할 수 있는 일이 없습니다.사용 가능한 유일한 대안은 SSL 연결 및 인증서 기반 인증을 사용하는 것입니다.

위의 방법은 SO에 대해 이미 논의되었으며 답변이 제공되었습니다.

앱 서버에서 데이터 소스 구성을 사용하는 것이 좋습니다.그리고 컨텍스트를 사용한 JNDI 조회를 사용하여 사용해 보십시오.

언급URL : https://stackoverflow.com/questions/23693796/where-should-i-keep-the-credentials-of-my-database

반응형