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

Overwrite for one single page in httpd.conf Therefore pay.html can be used as src of iframe on other domains

Header always append X-Frame-Options SAMEORIGIN

<Location /pay.html>
  # remove the SAMEORIGIN header
  Header always unset X-Frame-Options
</Location>

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

See targets in a target group

  1. Go to EC2
  2. In left side, under Load Balancing. Click Target Groups link
  3. Search target group by name. Click that target group
  4. In Registered targets section, see targets. They are running tasks. Find port
  5. Go to a task. Check the Network bindings for the task to find port. These ports are matched.

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