Thursday, January 9, 2025

How to Use OWASP Dependency Check in a Maven Project

OWASP Dependency Check is a software composition analysis (SCA) tool that scans your project's dependencies for known vulnerabilities. It cross-references dependencies with databases like the National Vulnerability Database (NVD) to help you proactively identify and mitigate risks in third-party libraries. This guide explains how to integrate and use OWASP Dependency Check in a Maven project.


What is OWASP Dependency Check?

OWASP Dependency Check is an open-source tool that:

  • Identifies vulnerabilities in project dependencies by referencing public vulnerability databases.
  • Helps mitigate risks by providing CVE details, severity levels, and suggested fixes.
  • Integrates seamlessly with Maven, Gradle, CI/CD pipelines, and other build tools.

Step 1: Add Dependency Check Plugin to Maven

To integrate Dependency Check with Maven, add the plugin configuration to your pom.xml:

<build>
<plugins> <plugin> <groupId>org.owasp</groupId> <artifactId>dependency-check-maven</artifactId> <version>8.4.0</version> <!-- Use the latest version --> <executions> <execution> <goals> <goal>check</goal> </goals> </execution> </executions> </plugin> </plugins> </build>

Step 2: Run the Dependency Check

Execute the following Maven command to start the vulnerability scan:

mvn dependency-check:check

Use mvn dependency-check:update-only on subsequent runs to reduce execution time.

What Happens:

  • The plugin scans your project's dependencies, fetches data from the NVD, and identifies vulnerabilities.
  • Reports are generated in the target directory:
    • HTML Report: dependency-check-report.html
    • JSON Report: dependency-check-report.json

Step 3: Review the Results

  1. Access the Reports:

    • Navigate to the target directory to view the generated reports.
    • Open dependency-check-report.html for a detailed summary.
  2. Understand the Output:

    • Each dependency is checked for known CVEs.
    • Severity is indicated using the CVSS (Common Vulnerability Scoring System).
  3. Take Action:

    • Update vulnerable dependencies to patched versions.
    • Exclude unused or unnecessary dependencies.

Step 4: Configure Dependency Check

Customize the plugin behavior to suit your project needs. Use the <configuration> tag in pom.xml for advanced settings.

Example Configuration:

<plugin>
<groupId>org.owasp</groupId> <artifactId>dependency-check-maven</artifactId> <version>8.4.0</version> <configuration> <outputDirectory>./dependency-check-reports</outputDirectory> <formats> <format>HTML</format> <format>JSON</format> </formats> <failBuildOnCVSS>7</failBuildOnCVSS> <!-- Fail build for CVSS >= 7 --> <nvd.api.key>your-nvd-api-key</nvd.api.key> <!-- Optional NVD API Key --> </configuration> </plugin>

Step 5: Enhance Performance with NVD API Key

The NVD API key helps:

  • Improve scan reliability by increasing request limits to the NVD database.
  • Reduce delays caused by throttling during frequent scans.

How to Use the API Key:

  1. Obtain an API Key:
  2. Configure the API Key:
    • Add it to your pom.xml:
      <configuration>
      <nvd.api.key>your-nvd-api-key</nvd.api.key> </configuration>
    • Or pass it via the command line:
      mvn dependency-check:check -Dnvd.api.key=your-nvd-api-key
    • Or set it as an environment variable:
      export NVD_API_KEY=your-nvd-api-key

Step 6: Automate with CI/CD

Integrate OWASP Dependency Check into your CI/CD pipeline to ensure continuous security validation.

GitHub Actions Example:

name: Dependency Check
on: push: branches: - main jobs: dependency-check: runs-on: ubuntu-latest steps: - name: Checkout Code uses: actions/checkout@v3 - name: Set up Java uses: actions/setup-java@v3 with: java-version: 11 - name: OWASP Dependency Check run: mvn dependency-check:check

Common Issues and Solutions

  1. Slow Scans:

    • Use an NVD API key for faster updates.
    • Run mvn dependency-check:update-only to pre-cache vulnerability data.
  2. False Positives:

    • Exclude specific dependencies:
      <configuration>
      <excludes> <exclude>com.example:example-dependency</exclude> </excludes> </configuration>
  3. Large Projects:

    • Adjust database refresh intervals:
      <cveValidForHours>72</cveValidForHours>

Tips for Best Practices

  1. Update Regularly:
    • Ensure the plugin and NVD database are up-to-date.
  2. Fail Builds on High-Risk Vulnerabilities:
    • Use <failBuildOnCVSS> to enforce a security threshold.
  3. Exclude Dev-Only Dependencies:
    • Use <scope>test</scope> for test dependencies that don’t need production scans.

Conclusion

OWASP Dependency Check is a vital tool for identifying and mitigating risks in your project's dependencies. By integrating it into your Maven project and CI/CD pipelines, you can proactively manage vulnerabilities and ensure compliance with security standards.

Wednesday, December 18, 2024

Debugging Azure Face API Errors with Python: Handling InvalidRequest

Introduction

While working with the Azure Face API to implement headshot validation, I encountered the following error during a face detection task:

Error during API call: (InvalidRequest) Invalid request has been sent.

This generic error provided no actionable information, making debugging difficult. To resolve the issue, I had to:

  • Dig deeper into the FaceClient SDK.
  • Enable logging to capture HTTP requests and responses.
  • Eventually uncover the root cause: the returnFaceId parameter.

This post will walk you through:

  1. How I identified and resolved the issue.
  2. Why the returnFaceId parameter caused the error.
  3. How to fix and debug similar issues in the Azure Face API.
  4. How to request approval for the returnFaceId feature.
  5. How to directly invoke the API for maximum control.

If you’re interested in headshot validation, check out my earlier post: Headshot Validation Using Azure Face API with Python.

Initial Code

Here’s the initial code I was using for face detection:

try:
with open(image_path, "rb") as image_stream:
print("Sending image to Azure Face API...")
detected_faces = face_client.face.detect_with_stream(
image=image_stream,
detection_model="detection_03" # Modern detection model
)
except Exception as e:
print(f"Error during API call: {e}")
return False

The output:

Error during API call: (InvalidRequest) Invalid request has been sent.

This generic message made it hard to debug the issue. I had no idea whether the problem was with my parameters, the image, or the API itself.

Adding Logging to Debug

To get more details, I enabled HTTP logging to capture the raw request and response sent to the Azure Face API. Here’s the updated code:

import logging

logging.basicConfig(level=logging.DEBUG) # Enable detailed logging

try:
with open(image_path, "rb") as image_stream:
print("Sending image to Azure Face API...")
detected_faces = face_client.face.detect_with_stream(
image=image_stream,
detection_model="detection_03" # Modern detection model
)
except Exception as e:
if hasattr(e, 'response') and e.response is not None:
print("Error during API call:")
print(f"HTTP Status Code: {e.response.status_code}")
print(f"Response Body: {e.response.text}")
else:
print(f"Error: {e}")
return False

The logs provided invaluable insights into the API behavior:

DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): xxxx.cognitiveservices.azure.com:443
DEBUG:urllib3.connectionpool:https://xxxx.cognitiveservices.azure.com:443 "POST /face/v1.0/detect?returnFaceId=true&returnFaceLandmarks=false&recognitionModel=recognition_01&returnRecognitionModel=false&detectionModel=detection_03&faceIdTimeToLive=86400 HTTP/11" 403 362
DEBUG:msrest.exceptions:(InvalidRequest) Invalid request has been sent.
Error during API call:
HTTP Status Code: 403
Response Body: {
"
error": {
"
code": "InvalidRequest",
"
message": "Invalid request has been sent.",
"
innererror": {
"
code": "UnsupportedFeature",
"
message": "Feature is not supported, missing approval for one or more of the following features: Identification,Verification. Please apply for access at https://aka.ms/facerecognition"
}
}
}

Root Cause: returnFaceId Defaults to True


The returnFaceId parameter in the Azure FaceClient SDK defaults to True, meaning the API tries to generate and return a unique Face ID for each detected face. This Face ID serves as a temporary identifier for the detected face, enabling workflows like face recognition, verification, and finding similar faces. The Face ID represents the face’s extracted features and can be used in subsequent API calls to match or compare faces.

 However:

  • This feature is restricted to approved customers only.
  • If you don’t have approval, the API rejects the request with an InvalidRequest error.

Since my application only required face detection (and not recognition tasks), I resolved the issue by explicitly setting return_face_id=False:

detected_faces = face_client.face.detect_with_stream(
image=image_stream,
detection_model="detection_03",
return_face_id=False # Explicitly exclude Face ID
)

Directly Invoking the Azure Face API

If you prefer full control over your API parameters, you can bypass the SDK and call the Azure Face API directly. This avoids SDK defaults like returnFaceId=True.

Using cURL

curl -X POST "https://your-endpoint.cognitiveservices.azure.com/face/v1.0/detect" \
-H "Content-Type: application/octet-stream" \
-H "Ocp-Apim-Subscription-Key: your_subscription_key" \
--data-binary "@your_image.jpg"

Using Python requests

import requests
FACE_API_KEY = "your_subscription_key"
FACE_API_ENDPOINT = "https://your-endpoint.cognitiveservices.azure.com/face/v1.0/detect"
headers = {
"Content-Type": "application/octet-stream",
"Ocp-Apim-Subscription-Key": FACE_API_KEY
}
params = {
"detectionModel": "detection_03"
}
with open("your_image.jpg", "rb") as image_stream:
response
= requests.post(FACE_API_ENDPOINT, headers=headers, params=params, data=image_stream)
print(response.json())

Direct API calls allow you to explicitly include or exclude parameters, ensuring greater flexibility.

How to Fix returnFaceId Errors

Set return_face_id=False:

  • Unless your application requires face recognition workflows, explicitly exclude Face IDs:
detected_faces = face_client.face.detect_with_stream(
image=image_stream,
detection_model="detection_03",
return_face_id=False
)

Request Approval for returnFaceId:

Best Practices for Debugging Azure Face API

Enable Logging:

  • Use Python’s logging module to capture HTTP requests and responses:
import logging
logging.basicConfig(level=logging.DEBUG)

Check API Documentation:

Use cURL for Simple Tests:

  • Test the API using cURL to isolate issues before implementing in Python.

Handle API Exceptions Gracefully:

  • Extract and print detailed responses from exceptions:
if hasattr(e, 'response') and e.response is not None:
print(f"HTTP Status Code: {e.response.status_code}")
print(f"Response Body: {e.response.text}")

Conclusion

The returnFaceId parameter is powerful for face recognition workflows but requires approval for use. If you don’t need face IDs, explicitly set return_face_id=False to avoid errors. For advanced use cases requiring face IDs, submit a request for access.

By adding logging and carefully reviewing the API response, you can effectively debug and resolve issues in the Azure Face API, making it a reliable tool for tasks like headshot validation and face detection.

For a practical implementation of headshot validation, check out my post: Headshot Validation Using Azure Face API.