session timer method что это
Asterisk 13 Configuration_res_pjsip
SIP Resource using PJProject
pjsip.conf
endpoint
Configuration Option Reference
Allow support for RFC3262 provisional ACK tags
Condense MWI notifications into a single NOTIFY.
Media Codec(s) to allow
Enable RFC3578 overlap dialing support.
AoR(s) to be used with the endpoint
Authentication Object(s) associated with the endpoint
CallerID information for the endpoint
Default privacy level
Internal id_tag for the endpoint
Dialplan context for inbound sessions
Mitigation of direct media (re)INVITE glare
Direct Media method type
Accept Connected Line updates from this endpoint
Send Connected Line updates to this endpoint
Connected line method type
Determines whether media may flow directly between endpoints.
Disable direct media session refreshes when NAT obstructs the media session
Media Codec(s) to disallow
IP address used in SDP for media handling
Bind the RTP instance to the media_address
Force use of return port
Enable the ICE mechanism to help traverse NAT
Way(s) for the endpoint to be identified
How redirects received from an endpoint are handled
NOTIFY the endpoint when state changes for any of the specified mailboxes
An MWI subscribe will replace sending unsolicited NOTIFYs
The voicemail extension to send in the NOTIFY Message-Account header
Default Music On Hold class
Authentication object(s) used for outbound requests
Full SIP URI of the outbound proxy used to send requests
Allow Contact header to be rewritten with the source IP address-port
Allow use of IPv6 for RTP traffic
Enforce that RTP must be symmetric
Send the Diversion header, conveying the diversion information to the called user agent
Send the History-Info header, conveying the diversion information to the called and calling user agents
Send the P-Asserted-Identity header
Send the Remote-Party-ID header
Immediately send connected line updates on unanswered incoming calls.
Minimum session timers expiration period
Session timers for SIP packets
Maximum session timer expiration period
Explicit transport configuration to use
Accept identification information received from this endpoint
Send private identification details to the endpoint.
Must be of type ‘endpoint’.
Use Endpoint’s requested packetization interval
Determines whether res_pjsip will use and enforce usage of AVPF for this endpoint.
Determines whether res_pjsip will use and enforce usage of AVP, regardless of the RTP profile in use for this endpoint.
Determines whether res_pjsip will use the media transport received in the offer SDP in the corresponding answer SDP.
Determines whether res_pjsip will use and enforce usage of media encryption for this endpoint.
Determines whether encryption should be used if possible but does not terminate the session if not achieved.
Force g.726 to use AAL2 packing order when negotiating g.726 audio
Determines whether chan_pjsip will indicate ringing using inband progress.
The numeric pickup groups for a channel.
The numeric pickup groups that a channel can pickup.
The named pickup groups for a channel.
The named pickup groups that a channel can pickup.
The number of in-use channels which will cause busy to be returned as device state
Whether T.38 UDPTL support is enabled or not
T.38 UDPTL error correction method
T.38 UDPTL maximum datagram size
Whether CNG tone detection is enabled
How long into a call before fax_detect is disabled for the call
Whether NAT support is enabled on UDPTL sessions
Whether IPv6 is used for UDPTL Sessions
Set which country’s indications to use for channels created for this endpoint.
Set the default language to use for channels created for this endpoint.
Determines whether one-touch recording is allowed for this endpoint.
The feature to enact when one-touch recording is turned on.
The feature to enact when one-touch recording is turned off.
Name of the RTP engine to use for channels created for this endpoint
Determines whether SIP REFER transfers are allowed for this endpoint
Determines whether a user=phone parameter is placed into the request URI if the user is determined to be a phone number
Determines whether hold and unhold will be passed through using re-INVITEs with recvonly and sendrecv to the remote side
String placed as the username portion of an SDP origin (o=) line.
String used for the SDP session (s=) line.
DSCP TOS bits for audio streams
DSCP TOS bits for video streams
Priority for audio streams
Priority for video streams
Determines if endpoint is allowed to initiate subscriptions with Asterisk.
The minimum allowed expiry time for subscriptions initiated by the endpoint.
Username to use in From header for requests to this endpoint.
Username to use in From header for unsolicited MWI NOTIFYs to this endpoint.
Domain to user in From header for requests to this endpoint.
Verify that the provided peer certificate is valid
Interval at which to renegotiate the TLS session and rekey the SRTP session
Path to certificate file to present to peer
Path to private key for certificate file
Cipher to use for DTLS negotiation
Path to certificate authority certificate
Path to a directory containing certificate authority certificates
Whether we are willing to accept connections, connect to the other party, or both.
Type of hash to use for the DTLS fingerprint in the SDP.
Determines whether 32 byte tags should be used instead of 80 byte tags.
Variable set on a channel involving the endpoint.
Context to route incoming MESSAGE requests to.
An accountcode to set automatically on any channels created for this endpoint.
Number of seconds between RTP comfort noise keepalive packets.
Maximum number of seconds without receiving RTP (while off hold) before terminating call.
Maximum number of seconds without receiving RTP (while on hold) before terminating call.
List of IP ACL section names in acl.conf
List of IP addresses to deny access from
List of IP addresses to permit access from
List of Contact ACL section names in acl.conf
List of Contact header addresses to deny
List of Contact header addresses to permit
Context for incoming MESSAGE requests.
Force the user on the outgoing Contact header to this value.
Allow the sending and receiving RTP codec to differ
Enable RFC 5761 RTCP multiplexing on the RTP port
Whether to notifies all the progress details on blind transfer
Whether to notifies dialog-info ‘early’ on InUse&Ringing state
Mailbox name to use when incoming MWI NOTIFYs are received
Follow SDP forked media when To tag is different
Accept multiple SDP answers on non-100rel responses
Suppress Q.850 Reason headers for this endpoint
Do not forward 183 when it doesn’t contain SDP
Configuration Option Descriptions
100rel
aggregate_mwi
When enabled, aggregate_mwi condenses message waiting notifications from multiple mailboxes into a single NOTIFY. If it is disabled, individual NOTIFYs are sent for each mailbox.
List of comma separated AoRs that the endpoint should be associated with.
This is a comma-delimited list of auth sections defined in pjsip.conf to be used to verify inbound connection attempts.
Endpoints without an authentication object configured will allow connections without verification.
Using the same auth section for inbound and outbound authentication is not recommended. There is a difference in meaning for an empty realm setting between inbound and outbound authentication uses. See the auth realm description for details.
callerid
callerid_privacy
direct_media_glare_mitigation
This setting attempts to avoid creating INVITE glare scenarios by disabling direct media reINVITEs in one direction thereby allowing designated servers (according to this option) to initiate direct media reINVITEs without contention and significantly reducing call setup time.
A more detailed description of how this option functions can be found on the Asterisk wiki https://wiki.asterisk.org/wiki/display/AST/SIP+Direct+Media+Reinvite+Glare+Avoidance
direct_media_method
Method for setting up Direct Media between endpoints.
connected_line_method
Method used when updating connected line information.
dtmf_mode
This setting allows to choose the DTMF mode for endpoint communication.
media_address
At the time of SDP creation, the IP address defined here will be used as the media address for individual streams in the SDP.
Be aware that the external_media_address option, set in Transport configuration, can also affect the final media address used in the SDP.
bind_rtp_to_media_address
If media_address is specified, this option causes the RTP instance to be bound to the specified ip address which causes the packets to be sent from that address.
identify_by
Endpoints and AORs can be identified in multiple ways. This option is a comma separated list of methods the endpoint can be identified.
This option controls both how an endpoint is matched for incoming traffic and also how an AOR is determined if a registration occurs. You must list at least one method that also matches for AORs or the registration will fail.
This method of identification has some security considerations because an Authentication header is not present on the first message of a dialog when digest authentication is used. The client can’t generate it until the server sends the challenge in a 401 response. Since Asterisk normally sends a security event when an incoming request can’t be matched to an endpoint, using this method requires that the security event be deferred until a request is received with the Authentication header and only generated if the username doesn’t result in a match. This may result in a delay before an attack is recognized. You can control how many unmatched requests are received from a single ip address before a security event is generated using the unidentified_request parameters in the «global» configuration object.
redirect_method
When a redirect is received from an endpoint there are multiple ways it can be handled. If this option is set to user the user portion of the redirect target is treated as an extension within the dialplan and dialed using a Local channel. If this option is set to uri_core the target URI is returned to the dialing application which dials it using the PJSIP channel driver and endpoint originally used. If this option is set to uri_pjsip the redirect occurs within chan_pjsip itself and is not exposed to the core at all. The uri_pjsip option has the benefit of being more efficient and also supporting multiple potential redirect targets. The con is that since redirection occurs within chan_pjsip redirecting information is not forwarded and redirection can not be prevented.
mailboxes
Asterisk will send unsolicited MWI NOTIFY messages to the endpoint when state changes happen for any of the specified mailboxes. More than one mailbox can be specified with a comma-delimited string. app_voicemail mailboxes must be specified as mailbox@context; for example: mailboxes=6001@default. For mailboxes provided by external sources, such as through the res_mwi_external module, you must specify strings supported by the external system.
For endpoints that SUBSCRIBE for MWI, use the mailboxes option in your AOR configuration.
outbound_auth
This is a comma-delimited list of auth sections defined in pjsip.conf used to respond to outbound connection authentication challenges.
Using the same auth section for inbound and outbound authentication is not recommended. There is a difference in meaning for an empty realm setting between inbound and outbound authentication uses. See the auth realm description for details.
rewrite_contact
On inbound SIP messages from this endpoint, the Contact header or an appropriate Record-Route header will be changed to have the source IP address and port. This option does not affect outbound messages sent to this endpoint. This option helps servers communicate with endpoints that are behind NATs. This option also helps reuse reliable transport connections such as TCP and TLS.
rpid_immediate
When enabled, immediately send 180 Ringing or 183 Progress response messages to the caller if the connected line information is updated before the call is answered. This can send a 180 Ringing response before the call has even reached the far end. The caller can start hearing ringback before the far end even gets the call. Many phones tend to grab the first connected line information and refuse to update the display if it changes. The first information is not likely to be correct if the call goes to an endpoint not under the control of this Asterisk box.
When disabled, a connected line update must wait for another reason to send a message with the connected line information to the caller before the call is answered. You can trigger the sending of the information by using an appropriate dialplan application such as Ringing.
timers_min_se
Minimum session timer expiration period. Time in seconds.
timers
timers_sess_expires
Maximum session timer expiration period. Time in seconds.
transport
This will force the endpoint to use the specified transport configuration to send SIP messages. You need to already know what kind of transport (UDP/TCP/IPv4/etc) the endpoint device will use.
Not specifying a transport will select the first configured transport in pjsip.conf which is compatible with the URI we are trying to contact.
Transport configuration is not affected by reloads. In order to change transports, a full Asterisk restart is required
trust_id_inbound
trust_id_outbound
use_avpf
force_avp
media_use_received_transport
media_encryption
media_encryption_optimistic
g726_non_standard
When set to «yes» and an endpoint negotiates g.726 audio then use g.726 for AAL2 packing order instead of what is recommended by RFC3551. Since this essentially replaces the underlying ‘g726’ codec with ‘g726aal2’ then ‘g726aal2’ needs to be specified in the endpoint’s allowed codec list.
inband_progress
call_group
Can be set to a comma separated list of numbers or ranges between the values of 0-63 (maximum of 64 groups).
pickup_group
Can be set to a comma separated list of numbers or ranges between the values of 0-63 (maximum of 64 groups).
named_call_group
Can be set to a comma separated list of case sensitive strings limited by supported line length.
named_pickup_group
Can be set to a comma separated list of case sensitive strings limited by supported line length.
device_state_busy_at
When the number of in-use channels for the endpoint matches the devicestate_busy_at setting the PJSIP channel driver will return busy as the device state instead of in use.
t38_udptl
If set to yes T.38 UDPTL support will be enabled, and T.38 negotiation requests will be accepted and relayed.
t38_udptl_ec
t38_udptl_maxdatagram
This option can be set to override the maximum datagram of a remote endpoint for broken endpoints.
fax_detect
This option can be set to send the session to the fax extension when a CNG tone is detected.
fax_detect_timeout
The option determines how many seconds into a call before the fax_detect option is disabled for the call. Setting the value to zero disables the timeout.
t38_udptl_nat
When enabled the UDPTL stack will send UDPTL packets to the source address of received packets.
t38_udptl_ipv6
When enabled the UDPTL stack will use IPv6.
record_on_feature
When an INFO request for one-touch recording arrives with a Record header set to «on», this feature will be enabled for the channel. The feature designated here can be any built-in or dynamic feature defined in features.conf.
This setting has no effect if the endpoint’s one_touch_recording option is disabled
record_off_feature
When an INFO request for one-touch recording arrives with a Record header set to «off», this feature will be enabled for the channel. The feature designated here can be any built-in or dynamic feature defined in features.conf.
This setting has no effect if the endpoint’s one_touch_recording option is disabled
Подводные камни использования сессий в PHP
Приветствую, уважаемое сообщество.
Прежде всего, хочу поблагодарить за очень полезный ресурс. Не раз находил здесь множество интересных идей и практических советов.
Цель этой статьи — осветить подводные камни использования сессий в PHP. Конечно, есть документация по PHP и масса примеров, и данная статья не претендует на полное руководство. Она призвана раскрыть некоторые ньюансы работы с сессиями и оградить разработчиков от ненужной траты времени.
Самым распространенным примером использования сессий является, конечно, авторизация пользователей. Начнем с самой базовой реализации, чтобы последовательно развивать ее по мере появления новых задач.
(В целях экономии места и времени ограничимся в примерах только самими функциями работы с сессиями, вместо того, чтобы строить здесь полноценное тестовое приложение с красивой иерархией классов, исчерпывающей обработкой ошибок и прочими правильными штуками).
Примечание: Подразумевается, что базовые знания о сессиях PHP у читателя имеются, поэтому принцип работы функций session_start() и session_destroy() освещать здесь не будем. Задачи верстки формы входа и аутентификации пользователя не относятся к теме статьи, поэтому их мы также опустим. Напомню только, что для идентификации пользователя в каждом последующем запросе, нам необходимо в момент успешного входа сохранить в сессионной переменной (с именем userid, например) идентификатор пользователя, который будет доступен во всех последующих запросах в пределах жизни сессии. Также необходимо реализовать обработку результата нашей функции startSession(). Если функция вернула FALSE — отобразить в браузере форму входа. Если функция вернула TRUE, и сессионная переменная, содержащая идентификатор авторизованного пользователя (в нашем случае — userid), существует — отобразить страницу авторизованного пользователя (подробнее об обработке ошибок см. дополнение от 2013-06-07 в разделе о сессионных переменных).
Пока все понятно. Вопросы начинаются, когда требуется реализовать контроль отсутствия активности пользователя (session timeout), дать возможность одновременной работы в одном браузере нескольких пользователей, а также защитить сессии от несанкционированного использования. Об этом и пойдет речь ниже.
Контроль отсутствия активности пользователя встроенными средствами PHP
Первый вопрос, который часто возникает у разработчиков всевозможных консолей для пользователей — автоматическое завершение сеанса в случае отсутствия активности со стороны пользователя. Нет ничего проще, чем сделать это с помощью встроенных возможностей PHP. (Этот вариант не отличается особой надежностью и гибкостью, но рассмотрим его для полноты картины).
Немного пояснений. Как известно, PHP определяет, какую именно сессию нужно запустить, по имени куки, передаваемом браузером в заголовке запроса. Браузер же, в свою очередь, получает этот куки от сервера, куда помещает его функция session_start(). Если время жизни куки в браузере истекло, он не будет передан в запросе, а значит PHP не сможет определить, какую сессию нужно запустить, и расценит это как создание новой сессии. Параметр настроек PHP session.gc_maxlifetime, который устанавливается равным нашему таймауту отсутствия активности пользователя, задает время жизни PHP-сессии и контролируется сервером. Работает контроль времени жизни сессии следующим образом (здесь рассматривается пример хранилища сессий во временных файлах как самый распространенный и установленный по умолчанию в PHP вариант).
Примечание: Здесь следует отметить, что параметр session.gc_maxlifetime действует на все сессии в пределах одного сервера (точнее, в пределах одного главного процесса PHP). На практике это значит, что если на сервере работает несколько сайтов, и каждый из них имеет собственный таймаут отсутствия активности пользователей, то установка этого параметра на одном из сайтов приведет к его установке и для других сайтов. То же касается и shared-хостинга. Для избежания подобной ситуации используются отдельные каталоги сессий для каждого сайта в пределах одного сервера. Установка пути к каталогу сессий производится с помощью параметра session.save_path в файле настроек php.ini, или путем вызова функции ini_set(). После этого сессии каждого сайта будут храниться в отдельных каталогах, и параметр session.gc_maxlifetime, установленный на одном из сайтов, будет действовать только на его сессии. Мы не станем рассматривать этот случай подробно, тем более, что у нас в запасе есть более гибкий вариант контроля отсутствия активности пользователя.
Контроль отсутствия активности пользователя с помощью сессионных переменных
Казалось бы, предыдущий вариант при всей своей простоте (всего пару дополнительных строк кода) дает все, что нам нужно. Но что, если не каждый запрос можно расценивать как результат активности пользователя? Например, на странице установлен таймер, который периодически выполняет AJAX-запрос на получение обновлений от сервера. Такой запрос нельзя расценивать как активность пользователя, а значит автоматическое продление времени жизни сессии является не корректным в данном случае. Но мы знаем, что PHP обновляет время модификации файла сессии автоматически при каждом вызове функции session_start(), а значит любой запрос приведет к продлению времени жизни сессии, и таймаут отсутствия активности пользователя не наступит никогда. К тому же, последнее примечание из предыдущего раздела о тонкостях работы параметра session.gc_maxlifetime может показаться кому-то слишком запутанным и сложным в реализации.
Для решения этой проблемы откажемся от использования встроенных механизмов PHP и введем несколько новых сессионных переменных, которые позволят нам контролировать время отсутствия активности пользователей самостоятельно.
Обработка результата функции sessionStart()
В комментариях обратили внимание на то, что возврат FALSE не дает полного понимания причины ошибки, и это абсолютно справедливо. Я не стал публиковать здесь подробную обработку ошибок (объем статьи и так не маленький), поскольку это не относится напрямую к теме статьи. Но учитывая комментарии, внесу ясность.
Как видно, функция sessionStart может вернуть FALSE в двух случаях. Либо сессию не удалось запустить из-за каких-то внутренних ошибок сервера (например, неправильные настройки сессий в php.ini), либо время жизни сессии истекло. В первом случае мы должны перебросить пользователя на страницу с ошибкой о том, что есть проблемы на сервере, и формой обращения в службу поддержки. Во втором случае мы должны перевести пользователя на форму входа и вывести в ней соответствующее сообщение о том, что время сессии истекло. Для этого нам необходимо ввести коды ошибок и возвращать вместо FALSE соответствующий код, а в вызывающем методе проверять его и действовать соответствующим образом.
Теперь, даже если сессия на сервере по-прежнему существует, она будет уничтожена при первом же обращении к ней, если таймаут отсутствия активности пользователя истек. И это произойдет независимо от того, какое время жизни сессий установлено в глобальных настройках PHP.
Примечание: А что произойдет, если браузер был закрыт, и куки с именем сессии был автоматически уничтожен? Запрос к серверу при следующем открытии браузера не будет содержать куки сессии, и сервер не сможет открыть сессию и проверить таймаут отсутствия активности пользователя. Для нас это равносильно созданию новой сессии и никак не влияет на функционал и безопасность. Но возникает справедливый вопрос — а кто же тогда уничтожит старую сессию, если до сих пор ее уничтожали мы по истечении таймаута? Или она теперь будет висеть в каталоге сессий вечно? Для очистки старых сессий в PHP существует механизм под названием garbage collection. Он запускается в момент очередного запроса к серверу и чистит все старые сессии на основании даты последнего изменения файлов сессий. Но запуск механизма garbage collection происходит не при каждом запросе к серверу. Частота (а точнее, вероятность) запуска определяется двумя параметрами настроек session.gc_probability и session.gc_divisor. Результат от деления первого параметра на второй и есть вероятностью запуска механизма garbage collection. Таким образом, для того, чтобы механизм очистки сессий запускался при каждом запросе к севреру, эти параметры нужно установить в равные значения, например «1». Такой подход гарантирует чистоту каталога сессий, но, очевидно, является слишком накладным для сервера. Поэтому в production-системах по умолчанию устанавливается значение session.gc_divisor, равное 1000, что означает, что механизм garbage collection будет запускаться с вероятностью 1/1000. Если вы поэкспериментируете с этими настройками в своем файле php.ini, то сможете заметить, что в описанном выше случае, когда браузер закрывается и очищает все свои куки, в каталоге сессий какое-то время все еще остаются старые сессии. Но это не должно вас волновать, т.к. как уже было сказано, это ни коим образом не влияет на безопасность нашего механизма.
Предотвращение зависания скриптов из-за блокировки файла сессии
В комментариях подняли вопрос о зависании одновременно выполняющихся скриптов из-за блокировки файла сессии (как самый яркий вариант — long poll).
Для начала отмечу, что эта проблема напрямую не зависит от загруженности сервера или количества пользователей. Конечно, чем больше запросов, тем медленнее выполняются скрипты. Но это коссвенная зависимость. Проблема появляется только в пределах одной сессии, когда серверу приходит несколько запросов от имени одного пользователя (например, один из них long poll, а остальные — обычные запросы). Каждый запрос пытается получить доступ к одному и тому же файлу сессии, и если предыдущий запрос не разблокировал файл, то последующий будет висеть в ожидании.
Для сведения блокировки файлов сессий к минимуму настоятельно рекомендуется закрывать сессию путем вызова функции session_write_close() сразу после того, как выполнены все действия с сессионными переменными. На практике это означает, что не следует хранить в сессионных переменных все подряд и обращаться к ним на всем протяжении выполнения скрипта. А если и надо хранить в сессионных переменных какие-то рабочие данные, то считывать их сразу при старте сессии, сохранять в локальные переменные для последующего использования и закрывать сессию (имеется ввиду закрытие сессии с помощью функции session_write_close, а не уничтожение с помощью session_destroy).
В нашем примере это означает, что сразу после открытия сессии, проверки времени ее жизни и существования авторизованного пользователя, мы должны считать и сохранить все дополнительные необходимые приложению сессионные переменные (если такие существуют), после чего закрыть сессию с помощью вызова session_write_close() и продолжить выполнение скрипта, будь то long poll или обычный запрос.
Защита сессий от несанкционированного использования
Представим себе ситуацию. Один из ваших пользователей цепляет троян, который грабит куки браузера (в котором хранится наша сессия) и отправляет его на указанный email. Злоумышленник получает куки и использует его для подделки запроса от имени нашего авторизованного пользователя. Сервер успешно принимает и обрабатывает этот запрос, как если бы он пришел от авторизованного пользователя. Если не реализована дополнительная проверка IP-адреса, такая атака приведет к успешному взлому аккаунта пользователя со всеми вытекающими последствиями.
Почему это стало возможным? Очевидно, потому что имя и идентификатор сессии всегда одни и те же на все время жизни сессии, и если получить эти данные, то можно беспрепятственно слать запросы от имени другого пользователя (естественно, в пределах времени жизни этой сессии). Возможно, это не самый распространенный вид атак, но теоретически все выглядит вполне реализуемым, особенно учитывая, что подобному трояну даже не нужны права администратора, чтобы грабить куки браузера пользователя.
Как же можно защититься от атак подобного рода? Опять-таки, очевидно, ограничив время жизни идентификатора сессии и периодически изменяя идентификатор в пределах одной сессии. Мы можем также изменять и имя сессии, полностью удаляя старую и создавая новую сессию, копируя в нее все сессионные переменные из старой. Но на суть подхода это не влияет, поэтому для простоты ограничимся только идентификатором сессии.
Понятно, что чем меньше время жизни идентификатора сессии, тем меньше будет времени у злоумышленника, чтобы получить и применить куки для подделки запроса пользователя. В идеальном случае для каждого запроса должен использоваться новый идентификатор, что позволит свести к минимуму возможность использования чужой сессии. Но мы рассмотрим общий случай, когда время регенерации идентификатора сессии устанавливается произвольно.
(Опустим ту часть кода, которая уже рассмотрена).
Итак, при создании новой сессии (которое происходит в момент успешного входа пользователя), мы устанавливаем сессионную переменную starttime, хранящую для нас время последней генерации идентификатора сессии, в значение, равное текущему времени сервера. Далее в каждом запросе мы проверяем, не прошло ли достаточно времени (idLifetime) с момента последней генерации идентификатора, и если прошло — генерируем новый. Таким образом, если в течение установленного времени жизни идентификатора злоумышленник, получивший куки авторизованного пользователя, не успеет им воспользоваться, поддельный запрос будет расценен сервером как неавторизованный, и злоумышленник попадет на страницу входа.
Примечание: Новый идентификатор сессии попадает в куки браузера при вызове функции session_regenerate_id(), которая отправляет новый куки, аналогично функции session_start(), поэтому нам нет необходимости обновлять куки самостоятельно.
Если мы хотим максимально обезопасить наши сессии, достаточно установить время жизни идентификатора в единицу или же вообще вынести функцию session_regenerate_id() за скобки и убрать все проверки, что приведет к регенерации идентификатора в каждом запросе. (Я не проверял влияние такого подхода на быстродействие, и могу только сказать, что функция session_regenerate_id(true) выполняет по сути всего 4 действия: генерация нового идентификатора, создание заголовка с куки сессии, удаление старого и создание нового файла сессии).
Лирическое отступление: Если троян окажется настолько умным, что не будет отправлять куки злоумышленнику, а сам организует отправку заранее подготовленного поддельного запроса сразу при получении куки, описанный выше метод, скорее всего, не сможет защитить от подобной атаки, потому что между временем получения трояном куки и отправкой поддельного запроса практически не будет разницы, и велика вероятность, что в этот момент не произойдет регенерации идентификатора сессии.
Возможность одновременной работы в одном браузере от имени нескольких пользователей
Последняя задача, которую хотелось бы рассмотреть — возможность одновременной работы в одном браузере нескольких пользователей. Эта возможность особенно полезна на этапе тестирования, когда нужно эмулировать одновременную работу пользователей, и желательно делать это в своем любимом браузере, а не использовать весь доступный арсенал или открывать несколько экземпляров браузера в режиме «инкогнито».
В наших предыдущих примерах мы не задавали явно имя сессии, поэтому использовалось имя, установленное в PHP по умолчанию (PHPSESSID). Это значит, что все сессии, которые создавались нами до сих пор, отправляли браузеру куки под именем PHPSESSID. Очевидно, что если имя куки всегда одинаковое, то нет возможности в пределах одного браузера организовать две сессии с одинаковым именем. Но если бы мы для каждого пользователя использовали собственное имя сессии, то проблема была бы решена. Так и сделаем.
Теперь осталось позаботиться о том, чтобы вызывающий скрипт передавал в функцию startSession() уникальный префикс для каждого пользователя. Это можно сделать, например, через передачу префикса в GET/POST параметрах каждого запроса или через дополнительный куки.
Заключение
В заключение приведу полный конечный код наших функций для работы с сессиями PHP, включающий все рассмотренные выше задачи.
Надеюсь, эта статья сэкономит немного времени тем, кто никогда особо не углублялся в механизм сессий, и даст достаточно понимания этого механизма тем, кто только начинает знакомиться с PHP.