소프트웨어 보안은 보안 소프트웨어가 아닙니다. 여기서는 인증, 액세스 제어, 기밀성, 암호화, 권한 관리 등의 항목에 대해 설명합니다.
URL url = new URL("https://myserver.org");
URLConnection urlConnection = url.openConnection();
InputStream in = urlConnection.getInputStream();
URLConnection
에 사용되는 기본 SSLSocketFactory
는 변경되지 않았기 때문에 Android 기본 키 저장소에 있는 모든 CA를 신뢰하는 기본 항목을 사용합니다.
val url = URL("https://myserver.org")
val data = url.readBytes()
URLConnection
에 사용되는 기본 SSLSocketFactory
는 변경되지 않았기 때문에 Android 기본 키 저장소에 있는 모든 CA를 신뢰하는 기본 항목을 사용합니다.
NSString* requestString = @"https://myserver.org";
NSURL* requestUrl = [NSURL URLWithString:requestString];
NSURLRequest* request = [NSURLRequest requestWithURL:requestUrl
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:10.0f];
NSURLConnection* connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
NSURLConnectionDelegate
메서드가 없기 때문에 iOS 기본 키 저장소에 있는 모든 CA를 신뢰하는 시스템을 사용합니다.
let requestString = NSURL(string: "https://myserver.org")
let requestUrl : NSURL = NSURL(string:requestString)!;
let request : NSURLRequest = NSURLRequest(URL:requestUrl);
let connection : NSURLConnection = NSURLConnection(request:request, delegate:self)!;
NSURLConnectionDelegate
메서드가 없기 때문에 iOS 기본 키 저장소에 있는 모든 CA를 신뢰하는 시스템을 사용합니다.
...
private bool CertificateCheck(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
...
return true;
}
...
HttpWebRequest webRequest = (HttpWebRequest) WebRequest.Create("https://www.myTrustedSite.com");
webRequest.ServerCertificateValidationCallback = CertificateCheck;
WebResponse response = webRequest.GetResponse();
...
...
SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, verify_callback);
...
...
config := &tls.Config{
// Set InsecureSkipVerify to skip the default validation
InsecureSkipVerify: true,
...
}
conn, err := tls.Dial("tcp", "example.com:443", conf)
..
...
Email email = new SimpleEmail();
email.setHostName("smtp.servermail.com");
email.setSmtpPort(465);
email.setAuthenticator(new DefaultAuthenticator(username, password));
email.setSSLOnConnect(true);
email.setFrom("user@gmail.com");
email.setSubject("TestMail");
email.setMsg("This is a test mail ... :-)");
email.addTo("foo@bar.com");
email.send();
...
smtp.mailserver.com:465
연결을 시도할 때 "hackedserver.com
"에 발급된 인증서를 즉시 수락합니다. 그러면 이제 응용 프로그램은 해킹당한 서버에 대한 손상된 SSL 연결에서 민감한 사용자 정보를 누출할 가능성이 있습니다.
...
var options = {
key : fs.readFileSync('my-server-key.pem'),
cert : fs.readFileSync('server-cert.pem'),
requestCert: true,
...
}
https.createServer(options);
...
https.Server
개체가 생성될 때 requestCert
설정이 true
로 지정되지만 rejectUnauthorized
가 설정되지 않습니다. 이는 false
에 대한 기본값입니다. 이렇게 되면 SSL을 통해 클라이언트를 확인하기 위해 서버를 생성해도, 제공된 CA 목록으로 인증서가 인증되지 않은 경우에도 연결이 수락되지 않습니다.
var tls = require('tls');
...
tls.connect({
host: 'https://www.hackersite.com',
port: '443',
...
rejectUnauthorized: false,
...
});
rejectUnauthorized
가 false로 설정되었으므로 인증되지 않은 인증서가 수락되고 확인되지 않은 서버로의 보안 연결도 생성됩니다. 그러면 이제 응용 프로그램은 해킹당한 서버에 대한 손상된 SSL 연결에서 민감한 사용자 정보를 누출할 가능성이 있습니다.NSURLConnectionDelegate
를 구성합니다.
implementation NSURLRequest (IgnoreSSL)
+ (BOOL)allowsAnyHTTPSCertificateForHost:(NSString *)host
{
return YES;
}
@end
Example 1
의 NSURLRequest
구현을 사용하여 SSL을 통해 보안이 유지되는 서버에 연결하려고 하면 요청된 서버의 인증서가 자체 서명된 인증서인 경우 확인되지 않으므로 경고나 오류가 생성되지 않습니다. 따라서 응용 프로그램이 이제 손상된 SSL 연결을 통해 민감한 사용자 정보를 누출하게 될 수도 있습니다.
...
import ssl
ssl_sock = ssl.wrap_socket(s)
...
require 'openssl'
...
ctx = OpenSSL::SSL::SSLContext.new
ctx.verify_mode=OpenSSL::SSL::VERIFY_NONE
...
NSURLConnectionDelegate
를 구성합니다.
class Delegate: NSObject, NSURLConnectionDelegate {
...
func connection(connection: NSURLConnection, canAuthenticateAgainstProtectionSpace protectionSpace: NSURLProtectionSpace?) -> Bool {
return protectionSpace?.authenticationMethod == NSURLAuthenticationMethodServerTrust
}
func connection(connection: NSURLConnection, willSendRequestForAuthenticationChallenge challenge: NSURLAuthenticationChallenge) {
challenge.sender?.useCredential(NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!), forAuthenticationChallenge: challenge)
challenge.sender?.continueWithoutCredentialForAuthenticationChallenge(challenge)
}
}
Example 1
의 NSURLConnectionDelegate
구현을 사용하여 SSL을 통해 보안이 유지되는 서버에 연결하려고 하면 요청된 서버의 인증서가 자체 서명된 인증서인 경우 확인되지 않으므로 경고나 오류가 생성되지 않습니다. 따라서 응용 프로그램이 이제 손상된 SSL 연결을 통해 민감한 사용자 정보를 누출하게 될 수도 있습니다.NSURLSession
클래스에서 SSL/TLS 체인 검증은 응용 프로그램의 인증 대리자 메서드에 의해 처리되지만, 사용자(또는 응용 프로그램)를 서버에 인증하기 위해 자격 증명을 제공하는 대신 응용 프로그램은 SSL/TLS 핸드셰이크 도중 서버가 제공하는 자격 증명을 확인한 다음 해당 자격 증명의 수락/거부 여부를 URL 로딩 시스템에 알립니다. 다음 코드는 수신한 챌린지의 proposedCredential
을 세션에 대한 자격 증명으로 다시 전달함으로써 서버 확인을 실제로 우회하는 NSURLSessionDelgate
를 보여 줍니다.
class MySessionDelegate : NSObject, NSURLSessionDelegate {
...
func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {
...
completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, challenge.proposedCredential)
...
}
...
}
...
FINAL(client) = cl_apc_tcp_client_manager=>create(
i_host = ip_adress
i_port = port
i_frame = VALUE apc_tcp_frame(
frame_type =
if_apc_tcp_frame_types=>co_frame_type_terminator
terminator =
terminator )
i_event_handler = event_handler ).
...
client
개체와 원격 서버 간 통신은 암호화되지 않고 인증되지 않은 채널을 통해 전송되므로 손상될 위험이 있습니다.
...
HttpRequest req = new HttpRequest();
req.setEndpoint('http://example.com');
HTTPResponse res = new Http().send(req);
...
HttpResponse
개체인 res
는 암호화 및 인증되지 않는 채널을 통해 제공되기 때문에 침해가 발생할 수 있습니다.
var account = new CloudStorageAccount(storageCredentials, false);
...
String url = 'http://10.0.2.2:11005/v1/key';
Response response = await get(url, headers: headers);
...
response
는 암호화 및 인증되지 않는 채널을 통해 제공되기 때문에 침해가 발생할 수 있습니다.
helloHandler := func(w http.ResponseWriter, req *http.Request) {
io.WriteString(w, "Hello, world!\n")
}
http.HandleFunc("/hello", helloHandler)
log.Fatal(http.ListenAndServe(":8080", nil))
URL url = new URL("http://www.android.com/");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
readStream(in);
...
}
instream
은 암호화 및 인증되지 않는 채널을 통해 제공되기 때문에 침해가 발생할 수 있습니다.
var http = require('http');
...
http.request(options, function(res){
...
});
...
http.IncomingMessage
개체인 res
는 암호화 및 인증되지 않는 채널을 통해 제공되기 때문에 침해가 발생할 수 있습니다.
NSString * const USER_URL = @"http://localhost:8080/igoat/user";
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:USER_URL]];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
...
stream_socket_enable_crypto($fp, false);
...
require 'net/http'
conn = Net::HTTP.new(URI("http://www.website.com/"))
in = conn.get('/index.html')
...
in
은 암호화 및 인증되지 않는 채널을 통해 제공되기 때문에 침해가 발생할 수 있습니다.
val url = Uri.from(scheme = "http", host = "192.0.2.16", port = 80, path = "/")
val responseFuture: Future[HttpResponse] = Http().singleRequest(HttpRequest(uri = url))
responseFuture
는 암호화 및 인증되지 않는 채널을 통해 제공되기 때문에 침해가 발생할 수 있습니다.
let USER_URL = "http://localhost:8080/igoat/user"
let request : NSMutableURLRequest = NSMutableURLRequest(URL:NSURL(string:USER_URL))
let conn : NSURLConnection = NSURLConnection(request:request, delegate:self)
Config.PreferServerCipherSuites
필드는 서버가 클라이언트 또는 서버의 암호 집합 기본 설정을 따르는지 여부를 제어합니다. 선택한 암호 집합에 알려진 취약성이 있는 경우, 클라이언트의 기본 암호 집합을 사용하면 보안 취약성이 발생할 수 있습니다.PreferServerCipherSuites
필드를 false
로 설정합니다.
conf := &tls.Config{
PreferServerCipherSuites: false,
}
client = SSHClient()
algorithms_to_disable = { "ciphers": untrusted_user_input }
client.connect(host, port, "user", "password", disabled_algorithms=algorithms_to_disable)
SSHClient.connect(...)
가 상대적으로 약한 알고리즘인 3DES-CBC를 사용하도록 강제할 수 있습니다.
...
Using(SqlConnection DBconn = new SqlConnection("Data Source=210.10.20.10,1433; Initial Catalog=myDataBase;User ID=myUsername;Password=myPassword;"))
{
...
}
...
...
insecure_config = {
'user': username,
'password': retrievedPassword,
'host': databaseHost,
'port': "3306",
'ssl_disabled': True
}
mysql.connector.connect(**insecure_config)
...
NSURLSession
, NSURLConnection
또는 CFURL
을 사용하는 경우 기본적으로 활성화되어 응용 프로그램과 백엔드 서버와의 모든 네트워크 통신에 HTTPS
와 TLS 1.2
를 사용할 것을 강제합니다.Info.plist
의 다음 항목은 ATS(App Transport Security)를 완전히 비활성화합니다.예제 2: 응용 프로그램
<key>NSAppTransportSecurity</key>
<dict>
<!--Include to allow all connections (DANGER)-->
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Info.plist
의 다음 항목은 yourserver.com
에 대해 ATS(App Transport Security)를 비활성화합니다.
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>yourserver.com</key>
<dict>
<!--Include to allow subdomains-->
<key>NSIncludesSubdomains</key>
<true/>
<!--Allow plain HTTP requests-->
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
<!--Downgrades TLS version-->
<key>NSTemporaryExceptionMinimumTLSVersion</key>
<string>TLSv1.1</string>
</dict>
</dict>
</dict>
<a href="http://www.example.com/index.html"/>
www.example.com
을 모방하거나 조작하여 자신의 웹 페이지를 로드할 수 있습니다.
...
using var channel = GrpcChannel.ForAddress("https://grpcserver.com", new GrpcChannelOptions {
Credentials = ChannelCredentials.Insecure
});
...
...
ManagedChannel channel = Grpc.newChannelBuilder("hostname", InsecureChannelCredentials.create()).build();
...
None
으로 설정됩니다. 이처럼 안전하지 않은 채널 자격 증명 설정을 사용하여 주고받는 데이터는 신뢰할 수 없습니다.root_certificates
매개 변수의 값은 None
으로, private_key
매개 변수의 값은 None
으로, certificate_chain
매개 변수의 값은 None
으로 설정됩니다.
...
channel_creds = grpc.ssl_channel_credentials()
...
...
Server server = Grpc.newServerBuilderForPort(port, InsecureServerCredentials.create())
...
None
또는 False
로 설정됩니다. 이처럼 안전하지 않은 서버 자격 증명 설정을 사용하는 서버와 주고받는 데이터는 신뢰할 수 없습니다.
...
pk_cert_chain = your_organization.securelyGetPrivateKeyCertificateChainPairs()
server_creds = grpc.ssl_server_credentials(pk_cert_chain)
...
HSTS
(HTTP Strict Transport Security) 헤더를 설정하지만 이 보호 기능을 하위 도메인에 적용하지 못해 공격자가 HTTPS 스트리핑 공격을 통해 하위 도메인 연결에서 민감한 정보를 훔칠 수 있습니다.HSTS
(HTTP Strict Transport Security)는 브라우저가 항상 HSTS 헤더를 헤더 내에 지정된 기간 동안 SSL/TLS를 통해 반환하는 사이트에 연결하도록 지시하는 보안 헤더입니다. HTTP를 통해 서버로 전송되는 모든 연결은 사용자가 브라우저의 URL 표시줄에 http://
를 입력하더라도 HTTPS 연결로 자동으로 바뀝니다.
<http auto-config="true">
...
<headers>
...
<hsts include-sub-domains="false" />
</headers>
</http>
HSTS
) 헤더를 설정하지만 이 보호 기능을 하위 도메인에 적용하지 못해 공격자가 HTTPS 스트리핑 공격을 통해 하위 도메인 연결에서 민감한 정보를 훔칠 수 있습니다.HSTS
)는 브라우저가 항상 HSTS 헤더를 헤더 자체에 지정된 기간 동안 SSL/TLS를 통해 반환하는 사이트에 연결하도록 지시하는 보안 헤더입니다. HTTP를 통해 서버로 전송되는 모든 연결은 사용자가 브라우저의 URL 표시줄에 http://
를 입력하더라도 HTTPS 연결로 자동으로 바뀝니다.HSTS
(HTTP Strict Transport Security) 헤더를 설정하지 않습니다. 이로 인해 공격자가 HTTPS 스트리핑 공격을 통해 SSL/TLS 연결을 일반 HTTP 연결로 바꾸고 민감한 정보를 훔칠 수 있습니다.HSTS
(HTTP Strict Transport Security)는 브라우저가 항상 HSTS 헤더를 헤더 내에 지정된 기간 동안 SSL/TLS를 통해 반환하는 사이트에 연결하도록 지시하는 보안 헤더입니다. HTTP를 통해 서버로 전송되는 모든 연결은 사용자가 브라우저의 URL 표시줄에 http://
를 입력하더라도 HTTPS 연결로 자동으로 바뀝니다.
<http auto-config="true">
...
<headers>
...
<hsts disabled="true" />
</headers>
</http>
HSTS
(HTTP Strict Transport Security) 헤더를 설정하지 않습니다. 이를 통해 공격자는 SSL/TLS 연결을 일반 HTTP 연결로 교체하고 HTTPS 스트리핑 공격을 수행하여 민감한 정보를 훔칠 수 있습니다.HSTS
)는 브라우저가 항상 HSTS 헤더를 헤더 자체에 지정된 기간 동안 SSL/TLS를 통해 반환하는 사이트에 연결하도록 지시하는 보안 헤더입니다. HTTP를 통해 서버로 전송되는 모든 연결은 사용자가 브라우저의 URL 표시줄에 http://
를 입력하더라도 HTTPS 연결로 자동으로 바뀝니다.HSTS
) 헤더를 설정하지 않아 공격자가 HTTPS 스트리핑 공격을 수행하여 SSL/TLS 연결을 일반 HTTP 연결로 바꾸고 민감한 정보를 훔칠 수 있습니다.HSTS
)는 브라우저가 항상 HSTS 헤더를 헤더 자체에 지정된 기간 동안 SSL/TLS를 통해 반환하는 사이트에 연결하도록 지시하는 보안 헤더입니다. HTTP를 통해 서버로 전송되는 모든 연결은 사용자가 브라우저의 URL 표시줄에 http://
를 입력하더라도 HTTPS 연결로 자동으로 바뀝니다.modp2
그룹을 사용하여 Diffie-Hellman 키 교환 프로토콜(1024비트 소수를 사용함)을 초기화합니다.
const dh = getDiffieHellman('modp2');
dh.generateKeys();
...
HSTS
(HTTP Strict Transport Security) 헤더를 부족한 만료 시간으로 설정합니다. 이로 인해 공격자가 HTTPS 스트리핑 공격을 수행하여 HTTPS 연결을 일반 HTTP 연결로 바꾸고 민감한 정보를 훔칠 수 있습니다.HSTS
(HTTP Strict Transport Security)는 브라우저가 항상 HSTS 헤더를 헤더 내에 지정된 기간 동안 SSL/TLS를 통해 반환하는 사이트에 연결하도록 지시하는 보안 헤더입니다. HTTP를 통해 서버로 전송되는 모든 연결은 사용자가 브라우저의 URL 표시줄에 http://
를 입력하더라도 HTTPS 연결로 자동으로 바뀝니다.
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
...
http.headers(headers ->
headers.httpStrictTransportSecurity(hstsConfig ->
hstsConfig.maxAgeInSeconds(300)
)
);
...
}
HSTS
) 헤더를 부족한 만료 시간으로 설정하여 공격자가 HTTPS 스트리핑 공격을 통해 HTTPS 연결을 일반 HTTP 연결로 바꾸고 민감한 정보를 훔칠 수 있습니다.HSTS
)는 브라우저가 항상 HSTS 헤더를 헤더 자체에 지정된 기간 동안 SSL/TLS를 통해 반환하는 사이트에 연결하도록 지시하는 보안 헤더입니다. HTTP를 통해 서버로 전송되는 모든 연결은 사용자가 브라우저의 URL 표시줄에 http://
를 입력하더라도 HTTPS 연결로 자동으로 바뀝니다.SmtpClient
는 SMTP 서버와 통신할 때 SSL/TLS를 사용하지 않도록 올바르지 않게 구성되어 있습니다.
string to = "bob@acme.com";
string from = "alice@acme.com";
MailMessage message = new MailMessage(from, to);
message.Subject = "SMTP client.";
message.Body = @"응용 프로그램에서 매우 쉽게 전자 메일을 전송할 수 있습니다.";
SmtpClient client = new SmtpClient("smtp.acme.com");
client.UseDefaultCredentials = true;
client.Send(message);
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="smtp.acme.com" />
<property name="port" value="25" />
<property name="javaMailProperties">
<props>
<prop key="mail.smtp.auth">true</prop>
</props>
</property>
</bean>
session = smtplib.SMTP(smtp_server, smtp_port)
session.ehlo()
session.login(username, password)
session.sendmail(frm, to, content)
device.createInsecureRfcommSocketToServiceRecord(MY_UUID);
...
var options = {
port: 443,
path: '/',
key : fs.readFileSync('my-server-key.pem'),
cert : fs.readFileSync('server-cert.pem'),
...
}
https.createServer(options);
...
secureProtocol
의 기본값을 SSLv23_method
로 설정하므로 서버는 secureProtocol
이 특별히 오버라이드되지 않으면 본질적으로 안전하지 않습니다.
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
[configuration setTLSMinimumSupportedProtocol = kSSLProtocol3];
NSURLSession *mySession = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:operationQueue];
let configuration : NSURLSessionConfiguration = NSURLSessionConfiguration.defaultSessionConfiguration()
let mySession = NSURLSession(configuration: configuration, delegate: self, delegateQueue: operationQueue)
...
encryptionKey = "".
...
...
var encryptionKey:String = "";
var key:ByteArray = Hex.toArray(Hex.fromString(encryptionKey));
...
var aes.ICipher = Crypto.getCipher("aes-cbc", key, padding);
...
...
char encryptionKey[] = "";
...
...
<cfset encryptionKey = "" />
<cfset encryptedMsg = encrypt(msg, encryptionKey, 'AES', 'Hex') />
...
...
key := []byte("");
block, err := aes.NewCipher(key)
...
...
private static String encryptionKey = "";
byte[] keyBytes = encryptionKey.getBytes();
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
Cipher encryptCipher = Cipher.getInstance("AES");
encryptCipher.init(Cipher.ENCRYPT_MODE, key);
...
...
var crypto = require('crypto');
var encryptionKey = "";
var algorithm = 'aes-256-ctr';
var cipher = crypto.createCipher(algorithm, encryptionKey);
...
...
CCCrypt(kCCEncrypt,
kCCAlgorithmAES,
kCCOptionPKCS7Padding,
"",
0,
iv,
plaintext,
sizeof(plaintext),
ciphertext,
sizeof(ciphertext),
&numBytesEncrypted);
...
...
$encryption_key = '';
$filter = new Zend_Filter_Encrypt($encryption_key);
$filter->setVector('myIV');
$encrypted = $filter->filter('text_to_be_encrypted');
print $encrypted;
...
...
from Crypto.Ciphers import AES
cipher = AES.new("", AES.MODE_CFB, iv)
msg = iv + cipher.encrypt(b'Attack at dawn')
...
require 'openssl'
...
dk = OpenSSL::PKCS5::pbkdf2_hmac_sha1(password, salt, 100000, 0) # returns an empty string
...
...
CCCrypt(UInt32(kCCEncrypt),
UInt32(kCCAlgorithmAES128),
UInt32(kCCOptionPKCS7Padding),
"",
0,
iv,
plaintext,
plaintext.length,
ciphertext.mutableBytes,
ciphertext.length,
&numBytesEncrypted)
...
...
Dim encryptionKey As String
Set encryptionKey = ""
Dim AES As New System.Security.Cryptography.RijndaelManaged
On Error GoTo ErrorHandler
AES.Key = System.Text.Encoding.ASCII.GetBytes(encryptionKey)
...
Exit Sub
...