items
, que comparte por defecto el contenido del portapapeles entre los dispositivos del usuario mediante Universal Clipboard.Ejemplo 2: En el siguiente código, los datos se escriben en el portapapeles general llamando al método
...
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
NSDictionary *items = @{
UTTypePlainText : sensitiveDataString,
UTTypePNG : [UIImage imageWithData:medicalImageData]
};
[pasteboard setItems: @[items]];
...
setObjects:localOnly:expirationDate:
con el comportamiento Universal Clipboard explícitamente habilitado configurando el parámetro localOnly
en NO
.
...
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
[pasteboard setObjects:@[sensitiveDataString, [UIImage imageWithData:medicalImageData]]
localOnly:NO
expirationDate:[NSDate distantFuture]];
...
setItems(_:options:)
, que comparte de forma predeterminada el contenido del portapapeles entre los dispositivos del usuario usando Universal Clipboard.Ejemplo 2: En el siguiente código, los datos se escriben en el portapapeles general utilizando el método
...
let pasteboard = UIPasteboard.general
let items: [[String: Any]] = [
["text": sensitiveDataString],
["image": UIImage(data: medicalImageData)!]
]
pasteboard.setItems(items)
...
setObjects(_:localOnly:expirationDate:)
con el comportamiento Universal Clipboard habilitado explícitamente configurando el parámetro localOnly
en false
.
...
let pasteboard = UIPasteboard.general
let items: [Any] = [
sensitiveDataString,
UIImage(data: medicalImageData)!
]
pasteboard.setObjects([items], localOnly: false, expirationDate: Date.distantFuture)
...
kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
:kSecAttrAccessibleAlways
:kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
:kSecAttrAccessibleAlwaysThisDeviceOnly
:kSecAttrAccessibleWhenUnlocked
:kSecAttrAccessibleWhenUnlockedThisDeviceOnly
:kSecAttrAccessibleAlways
, lo que creaba un problema de seguridad ya que si alguien tenía acceso a su dispositivo o lo robaba podía leer el contenido de las llaves. En la actualidad, el atributo predeterminado es kSecAttrAccessibleWhenUnlocked
, que es un valor predeterminado razonablemente restrictivo. Sin embargo, la documentación pública de Apple no está de acuerdo sobre cuál debe ser el atributo predeterminado. Por lo tanto, como precaución, debe configurar este atributo de manera explícita en todos los elementos de las llaves.
...
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
NSData *token = [@"secret" dataUsingEncoding:NSUTF8StringEncoding];
// Configure Keychain Item
[dict setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id) kSecClass];
[dict setObject:token forKey:(__bridge id)kSecValueData];
...
OSStatus error = SecItemAdd((__bridge CFDictionaryRef)dict, NULL);
...
kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
:kSecAttrAccessibleAlways
:kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
:kSecAttrAccessibleAlwaysThisDeviceOnly
:kSecAttrAccessibleWhenUnlocked
:kSecAttrAccessibleWhenUnlockedThisDeviceOnly
:kSecAttrAccessibleAlways
, lo que creaba un problema de seguridad ya que si alguien tenía acceso a su dispositivo o lo robaba podía leer el contenido de las llaves. En la actualidad, el atributo predeterminado es kSecAttrAccessibleWhenUnlocked
, que es un valor predeterminado razonablemente restrictivo. Sin embargo, la documentación pública de Apple no está de acuerdo sobre cuál debe ser el atributo predeterminado. Por lo tanto, como precaución, debe configurar este atributo de manera explícita en todos los elementos de las llaves.
...
// Configure Keychain Item
let token = "secret"
var query = [String : AnyObject]()
query[kSecClass as String] = kSecClassGenericPassword
query[kSecValueData as String] = token as AnyObject?
SecItemAdd(query as CFDictionary, nil)
...
...
if (tmpnam_r(filename)){
FILE* tmp = fopen(filename,"wb+");
while((recv(sock,recvbuf,DATA_SIZE, 0) > 0)&&(amt!=0))
amt = fwrite(recvbuf,1,DATA_SIZE,tmp);
}
...
tmpnam()
, tempnam()
, mktemp()
y sus equivalentes de C++ precedidos de un _
(carácter de subrayado), así como de la función GetTempFileName()
de la API de Windows. Este grupo de funciones presenta una condición de carrera subyacente en relación con el nombre de archivo seleccionado. Aunque las funciones garantizan que el nombre de archivo es exclusivo en el momento de seleccionarlo, no hay ningún mecanismo que impida que otro proceso o un usuario malintencionado cree un archivo con el mismo nombre tras seleccionarlo, pero antes de que la aplicación intente abrirlo. Más allá del riesgo de conflicto legítimo provocado por otra llamada a la misma función, hay una alta probabilidad de que un usuario malintencionado pueda crear un conflicto malicioso debido a que los nombres de archivo generados por estas funciones no son lo suficientemente aleatorios para que sean difíciles de adivinar.open()
mediante los indicadores O_CREAT
y O_EXCL
, o a CreateFile()
mediante el atributo CREATE_NEW
, que presentará errores si el archivo ya existe y, por lo tanto, impide los tipos de ataques descritos anteriormente. Sin embargo, si un usuario malintencionado puede predecir con precisión una secuencia de nombres de archivo temporales, es posible que se impida que la aplicación abra el almacenamiento temporal necesario, lo que provocaría un ataque de denegación de servicio (DoS). Este tipo de ataque no sería difícil de implementar dado el reducido nivel de aleatoriedad empleado en la selección de los nombres de archivo generados por estas funciones.tmpfile()
y sus equivalentes de C++ precedidos de _
(carácter de subrayado), así como de una función de biblioteca C mkstemp()
con un comportamiento más eficaz.tmpfile()
crean un nombre de archivo exclusivo y abren el archivo del mismo modo que lo haría fopen()
si transfiriese los indicadores "wb+"
, es decir, como un archivo binario en modo de lectura/escritura. Si el archivo ya existe, tmpfile()
se truncará para establecer el tamaño cero, posiblemente en un intento por apaciguar las inquietudes de seguridad mencionadas anteriormente en cuanto a la condición de carrera que se produce entre la selección del nombre de archivo supuestamente exclusivo y la posterior apertura del archivo seleccionado. Sin embargo, este comportamiento no soluciona claramente los problemas de seguridad de la función. En primer lugar, un atacante puede crear previamente el archivo con permisos de acceso moderados que probablemente conservará el archivo abierto por tmpfile()
. Además, en los sistemas basados en Unix, si el usuario malintencionado crea previamente el archivo como vínculo a otro archivo importante, la aplicación puede utilizar los permisos posiblemente elevados para truncar ese archivo, dañándolo en nombre del usuario malintencionado. Por último, si tmpfile()
crea un nuevo archivo, los permisos de acceso aplicados al mismo variarán de un sistema operativo a otro, lo que puede dejar vulnerable la aplicación, incluso aunque el usuario malintencionado pueda predecir por adelantado el nombre de archivo que se va a usar.mkstemp()
supone un método razonablemente seguro para crear archivos temporales. Este intentará crear y abrir un archivo exclusivo basado en una plantilla de nombre de archivo proporcionada por el usuario, junto con una serie de caracteres generados aleatoriamente. Si no puede crear este archivo, presentará errores y devolverá -1
. En los sistemas modernos, el archivo se abre mediante el modo 0600
, lo que implica que el archivo se protegerá frente a su manipulación a menos que el usuario cambie de forma explícita los permisos de acceso. No obstante, mkstemp()
aún presenta problemas en relación con el uso de nombres de archivo predecibles y puede dejar vulnerable una aplicación frente a ataques de denegación de servicio si un usuario malintencionado provoca que mkstemp()
presente fallos mediante la predicción y la creación previa de los nombres de archivo que se van a utilizar.
...
try:
tmp_filename = os.tempnam()
tmp_file = open(tmp_filename, 'w')
data = s.recv(4096)
while True:
more = s.recv(4096)
tmp_file.write(more)
if not more:
break
except socket.timeout:
errMsg = "Connection timed-out while connecting"
self.logger.exception(errMsg)
raise Exception
...
open()
mediante los indicadores os.O_CREAT
y os.O_EXCL
, que presentará errores si el archivo ya existe y, por lo tanto, impedirá los tipos de ataques descritos anteriormente. Sin embargo, si un usuario malintencionado puede predecir con precisión una secuencia de nombres de archivo temporales, es posible que se impida que la aplicación abra el almacenamiento temporal necesario, lo que provocaría un ataque de denegación de servicio (DoS). Este tipo de ataque no sería difícil de implementar dado el reducido nivel de aleatoriedad empleado en la selección de los nombres de archivo generados por estas funciones.tmpfile()
.tmpfile()
crean un nombre de archivo exclusivo y abren el archivo del mismo modo que lo haría open()
si transfiriese los indicadores "wb+"
, es decir, como un archivo binario en modo de lectura/escritura. Si el archivo ya existe, tmpfile()
se truncará para establecer el tamaño cero, posiblemente en un intento por apaciguar las inquietudes de seguridad mencionadas anteriormente en cuanto a la condición de carrera que se produce entre la selección del nombre de archivo supuestamente exclusivo y la posterior apertura del archivo seleccionado. Sin embargo, este comportamiento no soluciona claramente los problemas de seguridad de la función. En primer lugar, un atacante puede crear previamente el archivo con permisos de acceso moderados que probablemente conservará el archivo abierto por tmpfile()
. Además, en los sistemas basados en Unix, si el usuario malintencionado crea previamente el archivo como vínculo a otro archivo importante, la aplicación puede utilizar los permisos posiblemente elevados para truncar ese archivo, dañándolo en nombre del usuario malintencionado. Por último, si tmpfile()
crea un nuevo archivo, los permisos de acceso aplicados al mismo variarán de un sistema operativo a otro, lo que puede dejar vulnerable la aplicación, incluso aunque el usuario malintencionado pueda predecir por adelantado el nombre de archivo que se va a usar.
...
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
y el servidor remoto es vulnerable a compromisos, porque se transmite a través de un canal no cifrado y no autenticado.
...
HttpRequest req = new HttpRequest();
req.setEndpoint('http://example.com');
HTTPResponse res = new Http().send(req);
...
HttpResponse
, res
, se haya visto comprometido, ya que se proporciona a través de un canal no cifrado ni autenticado.
var account = new CloudStorageAccount(storageCredentials, false);
...
String url = 'http://10.0.2.2:11005/v1/key';
Response response = await get(url, headers: headers);
...
response
, se haya visto comprometida, ya que se proporciona a través de un canal no cifrado ni autenticado.
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
, se haya visto comprometida, ya que se proporciona a través de un canal no cifrado ni autenticado.
var http = require('http');
...
http.request(options, function(res){
...
});
...
http.IncomingMessage
, res
, se haya visto comprometido debido que se proporciona a través de un canal sin cifrar ni autenticar.
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
, se haya visto comprometida, ya que se proporciona a través de un canal no cifrado ni autenticado.
val url = Uri.from(scheme = "http", host = "192.0.2.16", port = 80, path = "/")
val responseFuture: Future[HttpResponse] = Http().singleRequest(HttpRequest(uri = url))
responseFuture
, se haya visto comprometida, ya que se proporciona a través de un canal no cifrado ni autenticado.
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
controla si el servidor sigue las preferencias de los conjuntos de cifrado del cliente o del servidor. Usar el conjunto de cifrado preferido por el cliente puede introducir vulnerabilidades de seguridad si se sabe que el conjunto de cifrado tiene deficiencias.PreferServerCipherSuites
como 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(...)
a utilizar el algoritmo más débil 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
, oCFURL
en iOS 9 o OS X El Capitan, lo que obliga a la aplicación a usar HTTPS
con TLS 1.2
en todas las comunicaciones de red con el servidor back-end.Info.plist
deshabilitarán por completo App Transport Security:Ejemplo 2: Las siguientes entradas de la aplicación
<key>NSAppTransportSecurity</key>
<dict>
<!--Include to allow all connections (DANGER)-->
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Info.plist
deshabilitarán App Transport Security para yourserver.com
:
<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
para cargar su propia página web.
...
using var channel = GrpcChannel.ForAddress("https://grpcserver.com", new GrpcChannelOptions {
Credentials = ChannelCredentials.Insecure
});
...
...
ManagedChannel channel = Grpc.newChannelBuilder("hostname", InsecureChannelCredentials.create()).build();
...
None
. No se puede confiar en los datos enviados con una configuración no segura de credenciales del canal.root_certificates
se configurará en None
, el valor del parámetro private_key
se configurará en None
y el valor del parámetro certificate_chain
se configurará en None
.
...
channel_creds = grpc.ssl_channel_credentials()
...
...
Server server = Grpc.newServerBuilderForPort(port, InsecureServerCredentials.create())
...
None
o False
. No se puede confiar en los datos enviados hacia un servidor y desde él con una configuración de credenciales no segura.
...
pk_cert_chain = your_organization.securelyGetPrivateKeyCertificateChainPairs()
server_creds = grpc.ssl_server_credentials(pk_cert_chain)
...
HSTS
), pero no puede aplicar esta protección a los subdominios, lo que permite que los atacantes roben información confidencial de las conexiones de subdominios mediante ataques de extracción de HTTPS.HSTS
) es un encabezado de seguridad que indica al explorador que siempre se conecte al sitio que devuelve los encabezados HSTS a través de SSL/TLS durante un período especificado dentro del encabezado. Cualquier conexión con el servidor mediante HTTP se reemplazará automáticamente por una HTTPS, incluso si el usuario escribe una URL con http://
en la barra de dirección URL del explorador.
<http auto-config="true">
...
<headers>
...
<hsts include-sub-domains="false" />
</headers>
</http>
HSTS
) pero no puede aplicar esta protección a los subdominios, lo que permite que los usuarios malintencionados roben información confidencial de las conexiones de subdominios mediante ataques de extracción de HTTPS.HSTS
) es un encabezado de seguridad que indica al explorador que siempre se conecte al sitio devolviendo los encabezados HSTS a través de SSL/TLS durante un período especificado en el encabezado en sí. Cualquier conexión con el servidor mediante HTTP se reemplazará automáticamente con una HTTPS, incluso si el usuario escribe http://
en la barra de dirección URL del explorador.HSTS
). Esto permite que los atacantes reemplacen las conexiones SSL/TLS por conexiones HTTP simples y roben información confidencial mediante ataques de extracción de HTTPS.HSTS
) es un encabezado de seguridad que indica al explorador que siempre se conecte al sitio que devuelve los encabezados HSTS a través de SSL/TLS durante un período especificado dentro del encabezado. Cualquier conexión con el servidor mediante HTTP se reemplazará automáticamente por una HTTPS, incluso si el usuario escribe una URL con http://
en la barra de dirección URL del explorador.
<http auto-config="true">
...
<headers>
...
<hsts disabled="true" />
</headers>
</http>
HSTS
), lo que permite a los atacantes reemplazar las conexiones SSL/TLS con simples conexiones HTTP y robar información confidencial, realizando ataques de eliminación de HTTPS.HSTS
) es un encabezado de seguridad que indica al explorador que siempre se conecte al sitio devolviendo los encabezados HSTS a través de SSL/TLS durante un período especificado en el encabezado en sí. Cualquier conexión con el servidor mediante HTTP se reemplazará automáticamente con una HTTPS, incluso si el usuario escribe http://
en la barra de dirección URL del explorador.HSTS
), lo que permite que los usuarios malintencionados reemplacen las conexiones SSL/TLS con HTTP sin formato y roben información confidencial mediante ataques de extracción de HTTPS.HSTS
) es un encabezado de seguridad que indica al explorador que siempre se conecte al sitio devolviendo los encabezados HSTS a través de SSL/TLS durante un período especificado en el encabezado en sí. Cualquier conexión con el servidor mediante HTTP se reemplazará automáticamente con una HTTPS, incluso si el usuario escribe http://
en la barra de dirección URL del explorador.modp2
predefinido para inicializar un protocolo de intercambio de claves Diffie-Hellman, que utiliza un valor primo de 1024 bits:
const dh = getDiffieHellman('modp2');
dh.generateKeys();
...
HSTS
) con un tiempo de vencimiento insuficiente. Esto permite que los atacantes reemplacen las conexiones HTTPS por conexiones HTTP simples y roben información confidencial mediante ataques de extracción de HTTPS.HSTS
) es un encabezado de seguridad que indica al explorador que siempre se conecte al sitio que devuelve los encabezados HSTS a través de SSL/TLS durante un período especificado dentro del encabezado. Cualquier conexión con el servidor mediante HTTP se reemplazará automáticamente por una HTTPS, incluso si el usuario escribe una URL con http://
en la barra de dirección URL del explorador.
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
...
http.headers(headers ->
headers.httpStrictTransportSecurity(hstsConfig ->
hstsConfig.maxAgeInSeconds(300)
)
);
...
}
HSTS
) con un tiempo de vencimiento insuficiente, lo que permite que los usuarios malintencionados reemplacen las conexiones HTTPS con otras HTTP sin formato y roben información confidencial mediante ataques de extracción de HTTPS.HSTS
) es un encabezado de seguridad que indica al explorador que siempre se conecte al sitio devolviendo los encabezados HSTS a través de SSL/TLS durante un período especificado en el encabezado en sí. Cualquier conexión con el servidor mediante HTTP se reemplazará automáticamente con una HTTPS, incluso si el usuario escribe http://
en la barra de dirección URL del explorador.SmtpClient
está configurado incorrectamente, no utiliza SSL/TLS para comunicarse con un servidor SMTP:
string to = "bob@acme.com";
string from = "alice@acme.com";
MailMessage message = new MailMessage(from, to);
message.Subject = "SMTP client.";
message.Body = @"You can send an email message from an application very easily.";
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
en SSLv23_method
, el servidor es inherentemente inseguro cuando secureProtocol
no se reemplaza específicamente.
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)
nresp = packet_get_int();
if (nresp > 0) {
response = xmalloc(nresp*sizeof(char*));
for (i = 0; i < nresp; i++)
response[i] = packet_get_string(NULL);
}
nresp
tiene el valor 1073741824
y sizeof(char*)
tiene su valor típico de 4
, el resultado de la operación nresp*sizeof(char*)
se desbordaría y el argumento de xmalloc()
sería 0
. La mayor parte de las implementaciones de malloc()
permitirán la asignación de un búfer de 0 bytes, lo que hará que las iteraciones de bucle posteriores desborden el búfer de montón response
.
char* processNext(char* strm) {
char buf[512];
short len = *(short*) strm;
strm += sizeof(len);
if (len <= 512) {
memcpy(buf, strm, len);
process(buf);
return strm + len;
} else {
return -1;
}
}
512
, la entrada no se procesará. El problema es que len
es un entero con signo, de modo que la comprobación en relación con la longitud máxima de la estructura se realiza con enteros con signo, pero len
se convierte en un entero sin signo para la llamada a memcpy()
. Si len
es negativo, parecerá que la estructura tiene un tamaño adecuado (se tomará la rama if
), pero la cantidad de memoria copiada por memcpy()
será bastante grande y el atacante podrá desbordar la pila con los datos de strm
.
77 accept-in PIC 9(10).
77 num PIC X(4) COMP-5. *> native 32-bit unsigned integer
77 mem-size PIC X(4) COMP-5.
...
ACCEPT accept-in
MOVE accept-in TO num
MULTIPLY 4 BY num GIVING mem-size
CALL "CBL_ALLOC_MEM" USING
mem-pointer
BY VALUE mem-size
BY VALUE 0
RETURNING status-code
END-CALL
num
tiene el valor 1073741824
, entonces el resultado de la operación MULTIPLY 4 BY num
desborda, y el argumento mem-size
a malloc()
será 0
. La mayoría de implementaciones de malloc()
ayudarán a la asignación de un búfer de 0 byte, lo que provocará que el búfer de salto mem-pointer
se desborde en declaraciones posteriores.
String arg = request.getParameter("arg");
...
Intent intent = new Intent();
...
intent.setClassName(arg);
ctx.startActivity(intent);
...