소프트웨어 보안은 보안 소프트웨어가 아닙니다. 여기서는 인증, 액세스 제어, 기밀성, 암호화, 권한 관리 등의 항목에 대해 설명합니다.
...
DSA dsa = new DSACryptoServiceProvider(1024);
...
...
DSA_generate_parameters_ex(dsa, 1024, NULL, 0, NULL, NULL, NULL);
...
...
dsa.GenerateParameters(params, rand.Reader, dsa.L1024N160)
privatekey := new(dsa.PrivateKey)
privatekey.PublicKey.Parameters = *params
dsa.GenerateKey(privatekey, rand.Reader)
...
...
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA", "SUN");
SecureRandom random = SecureRandom.getInstance("SHA256PRNG", "SUN");
keyGen.initialize(1024, random);
...
...
from Crypto.PublicKey import DSA
key = DSA.generate(1024)
...
require 'openssl'
...
key = OpenSSL::PKey::DSA.new(1024)
...
EVP_SignUpdate
메서드를 호출하는 단계를 건너뛰어 아무 데이터도 기반으로 하지 않는 서명이 생성됩니다.
...
rv = EVP_SignInit(ctx, EVP_sha512());
...
rv = EVP_SignFinal(ctx, sig, &sig_len, key);
...
update
메서드를 호출하는 단계를 건너뛰어 아무 데이터도 기반으로 하지 않는 서명이 생성됩니다.
...
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initSign(keyPair.getPrivate());
...
byte[] signatureBytes = sig.sign();
...
...
DSA dsa1 = new DSACryptoServiceProvider(Convert.ToInt32(TextBox1.Text));
...
key_len
을 확인할 수 있어야 하는 사용 사례는 거의 없으며, 설령 있다고 하더라도 해당 값이 숫자 값이며 적절한 키 크기 값 범위 내에 있는지 모두 확인하도록 적절한 보호 조치를 취해야 합니다. 대부분의 경우 이는 충분히 높은 하드코드된 숫자여야 합니다.
...
dsa.GenerateParameters(params, rand.Reader, key_len)
privatekey := new(dsa.PrivateKey)
privatekey.PublicKey.Parameters = *params
dsa.GenerateKey(privatekey, rand.Reader)
...
key_len
을 지정해야 하는 경우는 거의 없습니다. 키 길이를 지정해야 하는 경우에는 해당 값이 숫자 값이며 적절한 키 크기 값 범위 내에 있는지 모두 확인해야 합니다. 대부분의 경우에는 충분히 큰 하드코드된 키 크기를 선택합니다.
require 'openssl'
...
key_len = io.read.to_i
key = OpenSSL::PKey::DSA.new(key_len)
...
key_len
을 확인할 수 있어야 하는 사용 사례는 거의 없으며, 설령 있다고 하더라도 해당 값이 숫자 값이며 적절한 키 크기 값 범위 내에 있는지 모두 확인하도록 적절한 보호 조치를 취해야 합니다. 대부분의 경우 이는 충분히 높은 하드코드된 숫자여야 합니다.예제 2: 다음 코드는
Properties props = System.getProperties();
...
properties.setProperty("org.jcp.xml.dsig.secureValidation", "false");
XMLCryptoContext.setProperty
로 XML 서명 보안 유효성 검사를 비활성화합니다.
DOMCryptoContext cryptoContext = new DOMCryptoContext() {...};
...
cryptoContext.setProperty("org.jcp.xml.dsig.secureValidation", false);
...
CCCrypt(kCCEncrypt,
kCCAlgorithmDES,
kCCOptionPKCS7Padding,
key,
kCCKeySizeDES, // 64-bit key size
iv,
plaintext,
sizeof(plaintext),
ciphertext,
sizeof(ciphertext),
&numBytesEncrypted);
...
...
let iv = getTrueRandomIV()
...
let cStatus = CCCrypt(UInt32(kCCEncrypt),
UInt32(kCCAlgorithmDES),
UInt32(kCCOptionPKCS7Padding),
key,
keyLength,
iv,
plaintext,
plaintextLength,
ciphertext,
ciphertextLength,
&numBytesEncrypted)
...
String
으로 변환되므로 엔트로피가 크게 손실될 수 있습니다.String
으로 변환하는 경우String
으로 변환합니다.
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
...
KeyGenerator keygen = KeyGenerator.newInstance("AES");
...
SecretKey cryptoKey = keygen.generateKey();
byte[] rawCryptoKey = cryptoKey.getEncoded();
...
String key = new String(rawCryptoKey);
...
String
으로 변환합니다. 그러나 이 문자 집합의 유효한 범위 외부에서 생성자에 바이트를 제공할 때 수행되는 작업은 지정되지 않은 상태입니다. 따라서 key
에서는 원래 암호화 키 rawCryptoKey
에 비해 엔트로피가 크게 손실될 가능성이 높습니다.
static public byte[] EncryptWithRSA(byte[] plaintext, RSAParameters key) {
try {
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(key);
return rsa.Encrypt(plaintext, false);
}
catch(CryptographicException e) {
Console.WriteLine(e.Message);
return null;
}
}
void encrypt_with_rsa(BIGNUM *out, BIGNUM *in, RSA *key) {
u_char *inbuf, *outbuf;
int ilen;
...
ilen = BN_num_bytes(in);
inbuf = xmalloc(ilen);
BN_bn2bin(in, inbuf);
if ((len = RSA_public_encrypt(ilen, inbuf, outbuf, key, RSA_NO_PADDING)) <= 0) {
fatal("encrypt_with_rsa() failed");
}
...
}
...
import "crypto/rsa"
...
plaintext := []byte("Attack at dawn")
cipherText, err := rsa.EncryptPKCS1v15(rand.Reader, &k.PublicKey, plaintext)
...
public Cipher getRSACipher() {
Cipher rsa = null;
try {
rsa = javax.crypto.Cipher.getInstance("RSA/NONE/NoPadding");
}
catch (java.security.NoSuchAlgorithmException e) {
log("this should never happen", e);
}
catch (javax.crypto.NoSuchPaddingException e) {
log("this should never happen", e);
}
return rsa;
}
+ (NSData *) encryptData:(NSData *) plaintextData withKey:(SecKeyRef *) publicKey {
CFErrorRef error = nil;
NSData *ciphertextData = (NSData*) CFBridgingRelease(
SecKeyCreateEncryptedData(*publicKey,
kSecKeyAlgorithmRSAEncryptionPKCS1,
(__bridge CFDataRef) plaintextData,
&error));
if (error) {
// handle error ...
}
return ciphertextData;
}
function encrypt($input, $key) {
$output='';
openssl_public_encrypt($input, $output, $key, OPENSSL_NO_PADDING);
return $output;
}
...
from Crypto.PublicKey import RSA
message = 'Attack at dawn'
key = RSA.importKey(open('pubkey.der').read())
ciphertext = key.encrypt(message)
...
require 'openssl'
...
key = OpenSSL::PKey::RSA.new 2048
public_encrypted = key.public_encrypt(data) #padding type not specified
...
Example 1
에서 OpenSSL::PKey::RSA#public_encrypt
는 문자열로만 호출되며 사용할 패딩 유형을 지정하지 않습니다. 패딩의 기본값은 OpenSSL::PKey::RSA::PKCS1_PADDING
입니다.
func encrypt(data plaintextData:Data, publicKey:SecKey) throws -> Data {
var error: Unmanaged<CFError>?
guard let ciphertextData = SecKeyCreateEncryptedData(publicKey,
.rsaEncryptionPKCS1,
plaintextData as CFData,
&error) else {
throw error!.takeRetainedValue() as Error
}
return ciphertextData as Data;
}
...
Blob iv = Blob.valueOf('1234567890123456');
Blob encrypted = Crypto.encrypt('AES128', encKey, iv, input);
...
byte[] iv = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
using (SymmetricAlgorithm aesAlgo = SymmetricAlgorithm.Create("AES"))
{
...
aesAlgo.IV = iv;
...
}
unsigned char * iv = "12345678";
EVP_EncryptInit_ex(&ctx, EVP_idea_gcm(), NULL, key, iv);
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
)
...
block, err := aes.NewCipher(key)
...
mode := cipher.NewCBCEncrypter(block, key)
mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)
byte[] iv = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
IvParameterSpec ips = new IvParameterSpec(iv);
...
const iv = "hardcoded"
const cipher = crypto.createCipheriv("aes-192-ccm", key, iv)
...
NSString *iv = @"1234567812345678"; //Bad idea to hard code IV
char ivPtr[kCCBlockSizeAES128];
[iv getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSASCIIStringEncoding];
...
ccStatus = CCCrypt( kCCEncrypt,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding,
[key cStringUsingEncoding:NSASCIIStringEncoding],
kCCKeySizeAES128,
[ivPtr], /*IV should be something random (not null and not constant)*/
[self bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesEncrypted
);
nil
) 0만 포함된 IV가 사용됩니다.
from Crypto.Cipher import AES
from Crypto import Random
...
key = Random.new().read(AES.block_size)
cipher = AES.new(key, AES.MODE_CTR, IV=key)
require 'openssl'
...
cipher = OpenSSL::Cipher::AES.new('256-GCM')
cipher.encrypt
@key = cipher.random_key
cipher.iv=@key
encrypted = cipher.update(data) + cipher.final # encrypts data without hardcoded IV
...
...
let cStatus = CCCrypt(UInt32(kCCEncrypt),
UInt32(kCCAlgorithmAES128),
UInt32(kCCOptionPKCS7Padding),
key,
keyLength,
"0123456789012345",
plaintext,
plaintextLength,
ciphertext,
ciphertextLength,
&numBytesEncrypted)
nil
) 0만 포함된 IV가 사용됩니다.
...
var objAesCryptoService = new AesCryptoServiceProvider();
objAesCryptoService.Mode = CipherMode.ECB;
objAesCryptoService.Padding = PaddingMode.PKCS7;
objAesCryptoService.Key = securityKeyArray;
var objCrytpoTransform = objAesCryptoService.CreateEncryptor();
...
EVP_EncryptInit_ex(&ctx, EVP_aes_256_ecb(), NULL, key, iv);
...
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
ciphertext := make([]byte, aes.BlockSize+len(plaintext))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)
...
...
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
cipher.init(Cipher.ENCRYPT_MODE, key);
...
...
ccStatus = CCCrypt( kCCEncrypt,
kCCAlgorithmAES,
kCCOptionECBMode, // Uses ECB mode
key,
kCCKeySizeAES128,
iv,
plaintext,
sizeof(plaintext),
ciphertext,
sizeof(ciphertext),
&numBytesEncrypted);
...
from Crypto.Cipher import AES
from Crypto import Random
...
key = Random.new().read(AES.block_size)
random_iv = Random.new().read(AES.block_size)
cipher = AES.new(key, AES.MODE_ECB, random_iv)
require 'openssl'
...
cipher = OpenSSL::Cipher::AES.new('256-ECB')
...
ccStatus = CCCrypt(UInt32(kCCEncrypt),
UInt32(kCCAlgorithmAES128),
UInt32(kCCOptionECBMode),
keyData.bytes,
keyLength,
keyData.bytes,
data.bytes,
data.length,
cryptData.mutableBytes,
cryptData.length,
&numBytesEncrypted)
...
static public byte[] EncryptWithRSA(byte[] plaintext, RSAParameters key) {
try {
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(512);
rsa.ImportParameters(key);
return rsa.Encrypt(plaintext, true);
}
catch(CryptographicException e) {
Console.WriteLine(e.Message);
return null;
}
}
EVP_PKEY * get_RSA_key() {
unsigned long err;
EVP_PKEY * pkey;
RSA * rsa;
rsa = RSA_generate_key(512, 35, NULL, NULL);
if (rsa == NULL) {
err = ERR_get_error();
printf("Error = %s\n",ERR_reason_error_string(err));
return NULL;
}
pkey = EVP_PKEY_new();
EVP_PKEY_assign_RSA(pkey, rsa);
return pkey;
}
...
myPrivateKey := rsa.GenerateKey(rand.Reader, 1024);
...
public static KeyPair getRSAKey() throws NoSuchAlgorithmException {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(512);
KeyPair key = keyGen.generateKeyPair();
return key;
}
...
crmfObject = crypto.generateCRMFRequest(
"CN=" + name.value,
password.value,
authenticator,
keyTransportCert,
"setCRMFRequest();",
512, null, "rsa-dual-use");
...
...
CCCrypt(kCCEncrypt,
kCCAlgorithmDES,
kCCOptionPKCS7Padding,
key,
kCCKeySizeDES, // 64-bit key size
iv,
plaintext,
sizeof(plaintext),
ciphertext,
sizeof(ciphertext),
&numBytesEncrypted);
...
...
$keysize = 1024;
$options = array('private_key_bits' => $keysize, 'private_key_type' => OPENSSL_KEYTYPE_RSA);
$res = openssl_pkey_new($options);
...
...
from Crypto.PublicKey import RSA
key = RSA.generate(1024)
...
require 'openssl'
...
pkey = OpenSSL::PKey::RSA.new 1024
...
...
let iv = getTrueRandomIV()
...
let cStatus = CCCrypt(UInt32(kCCEncrypt),
UInt32(kCCAlgorithmDES),
UInt32(kCCOptionPKCS7Padding),
key,
UInt32(kCCKeySizeDES), // 64-bit key size
iv,
plaintext,
plaintextLength,
ciphertext,
ciphertextLength,
&numBytesEncrypted)
...
EVP_DecryptUpdate
에 대한 호출을 건너뛰어 암호화 텍스트를 해독하는 데 실패합니다.
...
EVP_DecryptInit_ex(&ctx, EVP_aes_256_gcm(), NULL, key, iv);
...
if(!EVP_DecryptFinal_ex(&ctx, outBuf+outBytes, &tmpOutBytes))
prtErrAndExit(1, "ERROR: EVP_DecryptFinal_ex did not work...\n");
...
KeyGenerator
의 초기화 단계를 건너뛰어 권장되는 키보다 작은 키를 사용하게 될 수 있습니다.
...
final String CIPHER_INPUT = "123456ABCDEFG";
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
SecretKey secretKey = keyGenerator.generateKey();
byte[] byteKey = secretKey.getEncoded();
....
OpenSSL::Cipher#update
에 대한 호출을 건너뛰어 암호화 텍스트를 해독하는 데 실패합니다.
require 'openssl'
...
decipher = OpenSSL::Cipher::AES.new(128, :GCM)
decipher.decrypt
decipher.key = key
decipher.iv = iv
plain = decipher.final #missed update method
...
import (
"crypto/aes"
"crypto/cipher"
"os"
)
...
iv = b'1234567890123456'
CTRstream = cipher.NewCTR(block, iv)
CTRstream.XORKeyStream(plaintext, ciphertext)
...
f := os.Create("data.enc")
f.Write(ciphertext)
f.Close()
Example 1
에서는 iv
가 상수 IV(Initialization Vector)로 설정되어 있으므로 재사용 공격에 취약해집니다.
...
const cipher = crypto.createCipheriv("AES-256-CTR", key, 'iv')
const ciphertext = cipher.update(plaintext, 'utf8');
cipher.final();
fs.writeFile('my_encrypted_data', ciphertext, function (err) {
...
});
from Crypto.Cipher import AES
from Crypto import Random
...
key = Random.new().read(AES.block_size)
iv = b'1234567890123456'
cipher = AES.new(key, AES.MODE_CTR, iv, counter)
...
encrypted = cipher.encrypt(data)
f = open("data.enc", "wb")
f.write(encrypted)
f.close()
...
Example 1
에서는 iv
가 상수 IV(Initialization Vector)로 설정되어 있으므로 재사용 공격에 취약해집니다.
require 'openssl'
...
cipher = OpenSSL::Cipher.new('AES-256-CTR')
cipher.encrypt
cipher.iv='iv'
...
encrypted = cipher.update(data) + cipher.final
File.open('my_encrypted_data', 'w') do |file|
file.write(encrypted)
end
Example 1
에서는 OpenSSL::Cipher#iv=
가 상수 IV(Initialization Vector)로 설정되어 있으므로 재사용 공격에 취약해집니다.
...
RSACryptoServiceProvider rsa1 = new RSACryptoServiceProvider(Convert.ToInt32(tx.Text));
...
Example 1
의 코드는 성공적으로 실행되지만 이 기능을 사용할 수 있는 사용자라면 누구나 tx.Text
텍스트 상자 값을 수정하여 암호화 알고리즘에 대한 키 크기 매개 변수를 조작할 수 있습니다. 프로그램을 공개한 후에는 악의적인 사용자가 지정된 암호화 작업의 키 크기를 알아내었는지 여부를 파악하기가 상당히 어렵기 때문에 사용자 제어 키 크기와 관련된 문제를 되돌리기가 힘들 수 있습니다.
...
rsa.GenerateKey(random, user_input)
...
Example 1
의 코드는 성공적으로 실행되지만 user_input
변수는 사용자가 제어할 수 있으므로 이 기능을 사용할 수 있는 사용자는 누구든지 암호화 알고리즘에 대해 키 크기 매개 변수를 조작할 수 있습니다. 소프트웨어 릴리스 후에는 사용자 제어 키 크기와 관련된 이슈를 해결하기가 힘들 수 있습니다. 악의적인 사용자가 지정된 암호화 작업의 키 크기를 알아내었는지 여부를 파악하기가 상당히 어렵기 때문입니다.
...
Properties prop = new Properties();
prop.load(new FileInputStream("config.properties"));
String keySize = prop.getProperty("keySize");
...
PBEKeySpec spec = new PBEKeySpec(
password.toCharArray(),
saltBytes,
pswdIterations,
Integer.parseInt(keySize)
);
SecretKey secretKey = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
...
Example 1
의 코드는 성공적으로 실행되지만 이 기능을 사용할 수 있는 사용자는 누구든지 keySize
속성을 수정하여 암호화 알고리즘에 대한 키 크기 매개 변수를 조작할 수 있습니다. 프로그램을 공개한 후에는 악의적인 사용자가 지정된 암호화 작업의 키 크기를 알아내었는지 여부를 파악하기가 상당히 어렵기 때문에 사용자 제어 키 크기와 관련된 문제를 되돌리기가 힘들 수 있습니다.
...
@property (strong, nonatomic) IBOutlet UITextField *inputTextField;
...
CCCrypt(kCCEncrypt,
kCCAlgorithmAES,
kCCOptionPKCS7Padding,
key,
sizeof(_inputTextField.text),
iv,
plaintext,
sizeof(plaintext),
ciphertext,
sizeof(ciphertext),
&numBytesEncrypted);
...
Example 1
의 코드는 성공적으로 실행되지만 이 기능을 사용할 수 있는 사용자는 누구든지 UITextField inputTextField
의 텍스트를 수정하여 암호화 알고리즘에 대한 키 크기 매개 변수를 조작할 수 있습니다. 프로그램을 공개한 후에는 악의적인 사용자가 지정된 암호화 작업의 키 크기를 알아내었는지 여부를 파악하기가 상당히 어렵기 때문에 사용자 제어 키 크기와 관련된 문제를 되돌리기가 힘들 수 있습니다.
...
$hash = hash_pbkdf2('sha256', $password, $random_salt, 100000, strlen($password));
...
Example 1
의 코드는 성공적으로 실행되지만 user_input
변수는 사용자가 제어할 수 있으므로 이 기능을 사용할 수 있는 사용자는 누구든지 암호화 알고리즘에 대해 키 크기 매개 변수를 조작할 수 있습니다. 프로그램을 공개한 후에는 악의적인 사용자가 지정된 암호화 작업의 키 크기를 알아내었는지 여부를 파악하기가 상당히 어렵기 때문에 사용자 제어 키 크기와 관련된 문제를 되돌리기가 힘들 수 있습니다.
...
dk = hashlib.pbkdf2_hmac('sha256', password, random_salt, 100000, dklen=user_input)
...
Example 1
의 코드는 성공적으로 실행되지만 user_input
변수는 사용자가 제어할 수 있으므로 이 기능을 사용할 수 있는 사용자는 누구든지 암호화 알고리즘에 대해 키 크기 매개 변수를 조작할 수 있습니다. 프로그램을 공개한 후에는 악의적인 사용자가 지정된 암호화 작업의 키 크기를 알아내었는지 여부를 파악하기가 상당히 어렵기 때문에 사용자 제어 키 크기와 관련된 문제를 되돌리기가 힘들 수 있습니다.
...
dk = OpenSSL::PKCS5.pbkdf2_hmac(password, random_salt, 100000, user_input, digest)
...
Example 1
의 코드는 성공적으로 실행되지만 user_input
변수는 사용자가 제어할 수 있으므로 이 기능을 사용할 수 있는 사용자는 누구든지 암호화 알고리즘에 대해 키 크기 매개 변수를 조작할 수 있습니다. 프로그램을 공개한 후에는 악의적인 사용자가 지정된 암호화 작업의 키 크기를 알아내었는지 여부를 파악하기가 상당히 어렵기 때문에 사용자 제어 키 크기와 관련된 문제를 되돌리기가 힘들 수 있습니다.
...
@IBOutlet weak var inputTextField : UITextField!
...
let key = (inputTextField.text as NSString).dataUsingEncoding(NSUTF8StringEncoding)
let keyPointer = UnsafePointer<UInt8>(key.bytes)
let keyLength = size_t(key.length)
...
let operation : CCOperation = UInt32(kCCEncrypt)
let algoritm : CCAlgorithm = UInt32(kCCAlgorithmAES128)
let options : CCOptions = UInt32(kCCOptionPKCS7Padding)
var numBytesEncrypted :size_t = 0
CCCrypt(operation,
algorithm,
options,
keyPointer,
keyLength,
iv,
plaintextPointer,
plaintextLength,
ciphertextPointer,
ciphertextLength,
&numBytesEncrypted)
...
Example 1
의 코드는 성공적으로 실행되지만 이 기능을 사용할 수 있는 사용자는 누구든지 UITextField inputTextField
의 텍스트를 수정하여 암호화 알고리즘에 대한 키 크기 매개 변수를 조작할 수 있습니다. 프로그램을 공개한 후에는 악의적인 사용자가 지정된 암호화 작업의 키 크기를 알아내었는지 여부를 파악하기가 상당히 어렵기 때문에 사용자 제어 키 크기와 관련된 문제를 되돌리기가 힘들 수 있습니다.doSecurityCheck()
는 보안 검사를 수행하고 하위 클래스로 오버라이드될 수 있습니다.
public class BadSecurityCheck {
private int id;
public BadSecurityCheck() {
doSecurityCheck();
id = 1;
}
protected void doSecurityCheck() {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new SomePermission("SomeAction"));
}
}
}
SecurityManager
권한이 허용되지 않으면 SecurityException
예외가 발생합니다. 이 예외는 런타임 예외이므로 프로그램이 더 이상 실행되지 않습니다. BadSecurityCheck
는 final
이 아니며 doSecurityCheck()
메서드는 final
이 아닌 protected
이므로 이 함수를 오버라이드하도록 이 클래스를 하위 클래스로 구분할 수 있습니다. doSecurityCheck()
가 하위 클래스에 의해 오버라이드됩니다.
public class EvilSubclass extends BadSecurityCheck {
private int id;
public EvilSubclass() {
super();
}
protected void doSecurityCheck() {
//do nothing
}
}
EvilSubclass
를 인스턴스화하면 구성자는 먼저 super()
를 호출해 슈퍼클래스의 구성자를 호출합니다. 그러면 doSecurityCheck()
함수가 호출됩니다. 하지만 Java는 슈퍼클래스를 확인하기 전에 하위 클래스 내에서 함수를 먼저 확인하므로 보안 검사를 무시하는 공격자 제어 메서드가 호출되기 때문에 id
는 계속 1
로 설정되어 있습니다.
<sp:TransportBinding>
<wsp:Policy>
<sp:TransportToken>
<wsp:Policy>
<sp:HttpToken/>
</wsp:Policy>
</sp:TransportToken>
...
</sp:TransportBinding>