Wednesday, 31 December 2025

AWS ECR image scan reports vulnerabilities

Question:When the image was scanned one month ago, there is no vulnerability. The same image is scanned today, and reports vulnerabilities. Why?

Answser: AWS has updated its' vulnerability definitions.

Question:Sometimes, after image is rebuilt using the same docker file, these vulnerabilities are gone. Why?

Answer: When the image is rebult, it will grab the latest libraries and these vulnerabilities may have been fixed in these new libraies. In the case, use this flag.

 --no-cache

Here is an example. Scan reports vulnerabilities related to curl

Dockerfile

FROM alpine:3.19
RUN apk update && apk add curl && apk upgrade

To build

 docker image build --no-cache  -t leo_test:latest .

When do apk update && apk add, it will get the latest libraries. At that time, alpine may have fix the curl issue. You may check and find that curl version has been changed.

curl --version

Tuesday, 30 December 2025

X-Frame-Options header for iframe

<iframe
        src="https://google.com"
        width="600"
        height="300"
        title="Demo Iframe"
        frameborder="0"
> </iframe>

Google.com will not be displayed in iframe. It is said that Google is refused to be connected. This is because that Google send out X-Frame-Options header

There are two values for this header

X-Frame-Options: DENY
X-Frame-Options: SAMEORIGIN

To set in apache httpd.conf

Header always append X-Frame-Options SAMEORIGIN
Header always append X-Frame-Options DENY

For the first option, will display content of the same domain. For the second option, will not display content from any domain

Thursday, 4 December 2025

ECS service and target group

  • associate ECS service to load balancer
  • define target group for load balancer
  • running tasks of this ECS service become targets of this target group
#cloudformation template snippet
Service:
    Type: "AWS::ECS::Service"
    Properties:
      Cluster: !FindInMap [BuildEnvironment, !Ref 'EnvironmentType', "cluster"]
      DesiredCount: !FindInMap [BuildEnvironment, !Ref 'EnvironmentType', "desire"]
      LoadBalancers:
        - ContainerName: !Sub "${EnvironmentType}-${APP}"
          ContainerPort: 80
          TargetGroupArn: my_target_group_arn

Monday, 1 December 2025

Encrypt and decrypt password using PHP sodium

Encrypt password

<?php
/**
 * encrypt.php
 */
$masterKey = "canyouguess";
$passwordToEncrypt = "top-secret";

//ecncypt password
$code = encrypt($masterKey, $passwordToEncrypt);
echo "code: ", $code, "\n";

/**
 * @param $masterKey
 * @param $password
 * @return string
 * @throws SodiumException
 */
function encrypt($masterKey, $password)
{
    // Derive a subkey of the correct length for secretbox
    $key = sodium_crypto_generichash($masterKey, '', SODIUM_CRYPTO_SECRETBOX_KEYBYTES
    );

    // Generate a random nonce
    $nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);

    // Encrypt
    $ciphertext = sodium_crypto_secretbox($password, $nonce, $key);

    // Prepend nonce for later decryption, and base64-encode the lot
    return base64_encode($nonce . $ciphertext);
}

In the directory of encrypt.php, run:

docker run -it --rm -v "$PWD":/usr/src -w /usr/src php:8.2-cli php encrypt.php

Output:

code: qKUilnBOnSPIOmKnwIoJAdOaC+9lhud/0eiTekLPokmuImFiRpuHvKG6AoUs7eT7fBY=

Decrypt code to get password

If do not have master key, there is no way to decrypt the code

<?php
/**
 * decrypt.php
 */

$masterKey = "canyouguess";
$code = "qKUilnBOnSPIOmKnwIoJAdOaC+9lhud/0eiTekLPokmuImFiRpuHvKG6AoUs7eT7fBY=";

//decrypt password using master key
$password = decrypt($masterKey, $code);
echo "password: ", $password, "\n";

/**
 * @param $masterKey
 * @param $code
 * @return string
 * @throws SodiumException
 */
function decrypt($masterKey, $code)
{
    $raw = base64_decode($code, true);
    if ($raw === false) {
        throw new RuntimeException('Invalid base64');
    }

    // same derived subkey
    $key = sodium_crypto_generichash($masterKey, '', SODIUM_CRYPTO_SECRETBOX_KEYBYTES
    );

    $nonceLen = SODIUM_CRYPTO_SECRETBOX_NONCEBYTES;
    if (strlen($raw) < $nonceLen) {
        throw new RuntimeException('Ciphertext too short');
    }

    // extract nonce and ciphertext
    $nonce = mb_substr($raw, 0, $nonceLen, '8bit');
    $ciphertext = mb_substr($raw, $nonceLen, null, '8bit');

    // decrypt & verify
    $plaintext = sodium_crypto_secretbox_open($ciphertext, $nonce, $key);
    if ($plaintext === false) {
        throw new RuntimeException('Decryption failed or message forged');
    }

    return $plaintext;
}

In the same directory of decrypt.php, run:

docker run -it --rm -v "$PWD":/usr/src -w /usr/src php:8.2-cli php decrypt.php

Output:

password: top-secret