Add certificate access protection
Any user who is logged in can explore all other users certificates simply by altering the parameter id in the url.
Given the user has id 4, the url reads:
https://myhostname/certificates/index.php?id=4
Changing the id to any other valid user id will show another users
certificate, if it exists:
https://myhostname/certificates/index.php?id=5
This is a huge privacy issue as it may reveal names and other personal user data that is included in the other users certificates. As a workaround I suggest to add the following check to /certificates/index.php somewhere below the lines
$certificate = new Certificate($certificateId, $userId);
$certificateData = $certificate->get($certificateId);
if (empty($certificateData)) {
api_not_allowed(false,
Display::return_message(get_lang('NoCertificateAvailable'), 'warning'));
}
// BEGIN WORKAROUND
if ( api_get_user_id() != $certificate->user_id ) {
api_not_allowed(true);
}
// END WORKAROUND
Beeing a workaround, this will even prevent admins or course admins from viewing students certificates.
This is correct. We assume (for now) that certificates are something you're proud to show off to others and allow other portal users to scan them. There is an effort for certificates and skills to be identified by an SHA hash rather than a sequential numerical ID in Chamilo 2.0.
There is an option (enabled by default) to prevent anonymous users to access certificates, but it doesn't block access from other registered users.

In EU and other coutries the DSGVO does not allow this. Everything that can identify an user by one self or by other persons by any informations is denied. So this Portal is not usable where the DSGVO is a law.
The only way is, that the user accept this on registration site with an active ok. And a double opt in for security! If he does not, this portal is not usable and this is not allowed by our law.
By the way, make your next release it's ok but in Germany (and i think EU also) this software release and older are not allowed!
@Bavarianspirit we are based in Europe. This is just an option. Feel free not to generate certificates to avoid the issue, or to include this as a requirement in your DSGVO/GDPR terms. There is no such thing as "not allowed" in the GDPR as long as you inform the users and allow them to decide they don't want to. By the way, printing names in certificates for other users on the same platform is the same as printing names in a students list in a hallway in a physical institution.
This feature request implies creating a new table with the list of certificates and their properties (when it was generated, for whom, linked to which resource (gradebook+course+session, whether the user wants it to be public or not, the old numeric ID and a new SHA string (not only based on this ID) to use in the URL to make it difficult to scan through).
State of the trade in 2025 : the gradebook_certificate table already has a user_id and a path_certificate that is generated from a (random?) hash. We're only missing an option for the user to say whether (s)he wants to publish it or not.
This would require (for now) an option as "gradebook_certificate.publish" (bool) which would be 0/false by default.
@christianbeeznest could you add that field to the 1.11 to 2.0 migration and to the gradebook_certificate entity?
Then we will have to fix all the certificates stuff because currently, the link points to the internal ID (instead of the hash) and is not working.
Hi @ywarnier ,
I've added the publish field (boolean, default false) to the gradebook_certificate entity and included it in the 1.11 to 2.0 migration — ready for alpha 3.
To complete the fix, could you please point me to a specific example (e.g. a page or component) where the certificate link is still using the internal ID instead of the path_certificate hash? That will help me identify the exact part that still needs to be updated.
Thanks!
Sure you can test it on https://testing26.beeznest.com/
Login as the admin user, go to https://testing26.beeznest.com/main/user/user.php?cid=4&gid=0 and click "login as" for user "rgardner".
Enter course https://testing26.beeznest.com/course/4/home (English for beginners), get into the Assessments tool, click "Display certificate" on the right. You can see this has path https://testing26.beeznest.com/certificates/index.php?id=1&user_id=38 and it fails. The path should be https://testing26.beeznest.com/certificates/37b73510175057c633ebe4beb0a34917fa2a0696432db43a4eeb2c3ff83a4c3b.html or something similar. This link, should go through a controller that verifies if the certificates in general are public (global setting in Chamilo, shown in previous comments) and that the new field (publish) is set to 1. If both are true, than anyone can look at the certificate at https://testing26.beeznest.com/certificates/37b73510175057c633ebe4beb0a34917fa2a0696432db43a4eeb2c3ff83a4c3b.html. Otherwise an error message indicates "The requested certificate does not exist." or "The requested certificate is not public.".
You can also see that the "Download certificate in PDF" button fails. That is probably because the other one fails, as the export to PDF is an export of the HTML version to PDF or something like that. This link (to the PDF) should never be public.
The "Download report in PDF" seems to work fine. Not an issue.
Thank you @ywarnier , it is implemented with this PR https://github.com/chamilo/chamilo-lms/pull/6343
Thanks for confirmation.
I'm not sure exactly what went wrong here but this isn't working. Now, when I get into a course as a student, if I finish the requirements to get a certificate and I go to the assessment tool, I do not see a "Display certificate" link anymore. This might be linked to this change of conditions : https://github.com/chamilo/chamilo-lms/pull/6343/files#diff-456a921fb68d231748462a79197fcf71f6561b4662aad0b3dcba9f259e5fc1fcR2105
Normally, when the user gets into the assessment tool for the first time after having completed the requirements to obtain a certificate, the certificate should get generated right there and the link should show.
There's also an issue at https://github.com/chamilo/chamilo-lms/pull/6343/files#diff-4055e6d5a2b2f4d2700acff2561853a29538838371852c2a23ac1cc6573acbb3R46 If the user is logged in and is the owner of the certificate or it's a privileged user (admin or course teacher in this course), then the certificate should be visible. It's only for people that have nothing to do with the certificate that the blocking mechanism is used.
So here https://github.com/chamilo/chamilo-lms/pull/6343/files#diff-456a921fb68d231748462a79197fcf71f6561b4662aad0b3dcba9f259e5fc1fcR2100 we should only check "publish" if it's not the owner or a related privileged user before displaying the link. And here https://github.com/chamilo/chamilo-lms/pull/6343/files#diff-4055e6d5a2b2f4d2700acff2561853a29538838371852c2a23ac1cc6573acbb3R45 and probably here https://github.com/chamilo/chamilo-lms/pull/6343/files#diff-4055e6d5a2b2f4d2700acff2561853a29538838371852c2a23ac1cc6573acbb3R78 also.
@christianbeeznest don't forget about this one 👈
Yes @ywarnier , it is fixed with this commit now https://github.com/chamilo/chamilo-lms/pull/6452/commits/b49bfcb8a082f4ebff908abcbe3c587fbb2e6d54
Thank you.
OK, the button now appears, but when I click on it (as a user logged in with "login as") I get an AccessDenied exception: From https://testing26.beeznest.com/main/gradebook/index.php?cid=5&gid=0 I click and:
Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException:
The requested certificate is not public.
at src/CoreBundle/Controller/CertificateController.php:56
at Chamilo\CoreBundle\Controller\CertificateController->view()
(vendor/symfony/http-kernel/HttpKernel.php:181)
at Symfony\Component\HttpKernel\HttpKernel->handleRaw()
(vendor/symfony/http-kernel/HttpKernel.php:76)
at Symfony\Component\HttpKernel\HttpKernel->handle()
(vendor/symfony/http-kernel/Kernel.php:197)
at Symfony\Component\HttpKernel\Kernel->handle()
(vendor/symfony/runtime/Runner/Symfony/HttpKernelRunner.php:35)
at Symfony\Component\Runtime\Runner\Symfony\HttpKernelRunner->run()
(vendor/autoload_runtime.php:29)
at require_once('/var/www/testing26.beeznest.com/www/vendor/autoload_runtime.php')
(public/index.php:8)
I'm looking at it myself.
Images are still an issue for certificates, but the "publish" element from this task is done